推荐使用yarn包管理工具替代npm

yarn确实很快!使用流程上特别爽!下载安装 yarnpkg,并进行国内镜像配置

1
2
3
4
5
6
7
8
yarn config set registry https://registry.npm.taobao.org -g
yarn config set disturl https://npm.taobao.org/dist -g
yarn config set electron_mirror https://npm.taobao.org/mirrors/electron/ -g
yarn config set sass_binary_site https://npm.taobao.org/mirrors/node-sass/ -g
yarn config set phantomjs_cdnurl https://npm.taobao.org/mirrors/phantomjs/ -g
yarn config set chromedriver_cdnurl https://cdn.npm.taobao.org/dist/chromedriver -g
yarn config set operadriver_cdnurl https://cdn.npm.taobao.org/dist/operadriver -g
yarn config set fse_binary_host_mirror https://npm.taobao.org/mirrors/fsevents -g

另外,yarn 还可以直接添加远程 git 的包!这个NPM是不支持的,已经不再维护的 Bower 也是支持的。

常用命令

添加依赖包

1
2
3
yarn add [package]
yarn add [package]@[version]
yarn add [package]@[tag]

升级依赖包

1
2
3
yarn upgrade [package]
yarn upgrade [package]@[version]
yarn upgrade [package]@[tag]

移除依赖包

1
yarn remove [package]

安装项目的全部依赖

1
yarn

yarn bin

yarn bin 将打印 yarn 将把你的包里可执行文件安装到的目录。

yarn run

类似npm run,此命令可以运行定义在package.json的script, 也可以像 npx <package-cli-name> 一样运行node_modules的可执行文件

yarn global

global关键字必须放在yarn后面,

  • yarn add: 添加一个包用在你当前的项目里。
  • yarn bin: 显示 yarn bin 目录的位置。
  • yarn list: 列出已安装的包。
  • yarn remove: 从你当前包里移除一个不再使用的包。
  • yarn upgrade: 基于指定的范围把包升级到它们最新版本。

yarn info []

这个命令会拉取包的信息并返回为树格式,包不必安装到本地。

1
yarn info react

理解 JS 作用域和 this

1
2
3
4
(function(){
var a = b =1;
})()
console.log(b)

答案:1。定义变量如果不使用 var 则变量为为全局作用域。当然严格模式是禁止这样做的。

当查找变量的时候,会先从当前上下文的变量对象中查找,如果没有找到,就会从父级(词法层面上的父级)执行上下文的变量对象中查找,一直找到全局上下文的变量对象,也就是全局对象。

1
2
3
4
5
6
7
8
function test() {
// 这里就是 a =1
console.log(a);
// 然后再赋值
var a = 1;
}

test();

这里的变量a进行了提升,先定义(!把定义提升!)后(!在其赋值位置!)赋值,如果不存在 var 就不会提升,接着就是未定义报错。而函数表达式(function t(){} )会提升最高,如果用 var t = function (){} 的形式则根据变量原则提升。而在 ES6 中使用 let 和 const 不存在提升。

1
2
3
4
5
6
7
8
9
10
11
function test() {
console.log(1);
}

test();

var test = function() {
console.log(2);
};

test();

这里就会输出 1 和 2。

1
2
3
4
5
6
7
8
var a =20;
function t1(){
console.log(a)
}
(function t2() {
var a = 10;
t1()
})()
1
2
3
4
5
6
7
8
9
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f();
}
checkscope();
1
2
3
4
5
6
7
8
9
var scope = "global scope";
function checkscope(){
var scope = "local scope";
function f(){
return scope;
}
return f;
}
checkscope()();

答案:20, “local scope” , “local scope”。JS 遵循词法作用域原则,函数的作用域在函数定义的时候就决定了,执行函数时先从函数内部查找是否有局部变量,如果没有就在定义的位置查找上面一层作用域,其中后两题来源于《JavaScript权威指南》。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
var a = 20;

var obj = {
a: 40,
test() {
var a = 10;
console.log(this.a)
}
}
// Q1
obj.test();
// Q2
var t = obj.test;
t();
// Q3
(obj.test)();
// Q4
(obj.test, obj.test)()

答案:40,20,40,20。非箭头函数下的 this 指向运行时所在作用域。Q4 中逗号操作符会从左到右计算它的操作数,返回最后一个操作数的值。

必须说一下最后一个,Q3 为什么 this 指向的 obj,而 Q4 中 this 指向的是 window(非严格模式)? 这里有一个技巧就是如果对象属性参与了计算,在 es 规范中就是 [GetValue] 就会失去对原对象的 this ,Q3 中圆括号没有参与计算,而 Q4 参与了计算。

类如

1
2
3
(foo.bar = foo.bar)()
(false || foo.bar)()
(foo.bar, foo.bar)()

这里的 this 都会指向 undefined(非严格模式指向全局对象)

再比如说,这里的 this 也会指向 undefined

1
2
3
4
5
6
7
8
9
10
11
12
var obj = {
name: "obj",
getName: function() {
console.log(this === global);
}
};

function test(fn) {
fn();
}
// 这里是在node环境
test(obj.getName);

接着看看绑定函数

1
2
3
4
5
6
7
8
9
10
11
12
13
var o1 = {
name: "o1"
};

var o2 = {
name: "o2"
};

function getName() {
console.log(this.name);
}

getName.bind(o1).call(o2);

bind 绑定后,不在进行this再绑定,所以答案为 “o1”

再看看箭头函数,不要被定义时this这个知识欺骗了。

1
2
3
4
5
6
7
8
var o2 = {
name: "o2",
getName: () => console.log(this === window),
doItRight: function() {
() => console.log(this === o2);
}
};
o2.getName(); // true

你不应该这样简写,而是应该使用对象方法属性方式简写

1
2
3
4
5
6
var o2 = {
name: "o2",
getName() {
console.log(this === o2)
}
};

Linux下解决修改文件权限引起的Git记录文件变化问题

git默认会跟踪web文件夹的权限修改,当我们使用chmod指令的时候,git也会把被修改权限的文件添加到被修改的状态。

因为 laravel 部署在生产环境中的时候,需要对 storage 目录进行赋权,不过正是因为如此,当我们运行 git status 的时候会莫名的把 storage 目录所有的 .gitignore 文件添加到 git 缓存区。

image

首先在项目下 cat .git/config 查看是否已经设置忽略文件权限,filemode=true 的时候即跟踪修改权限的文件 。

image

这时候我们只要简单的运行git config core.filemode false就可以了,然后我们运行git status那些被修改权限的文件已经不存在了。

使用certbot免费升级到https

使用certbot免费升级到https

环境为 Ubuntu Server 16.04 和 Nginx,具体可参考官网,letsencrypt是certbot以前的名称,github的地址也重定向到certbot了。

Certbot, previously the Let’s Encrypt Client, is EFF’s tool to obtain certs from Let’s Encrypt, and (optionally) auto-enable HTTPS on your server. It can also act as a client for any other CA that uses the ACME protocol.

安装依赖

  1. sudo apt-get update
  2. sudo apt-get install python2.7 git -y
  3. sudo apt-get install software-properties-common

下载certbot


  1. git clone https://github.com/certbot/certbot.git
  2. cd certbot

新方式:

$ sudo add-apt-repository ppa:certbot/certbot
$ sudo apt-get update
$ sudo apt-get install python-certbot-nginx

不重启获取证书

./certbot-auto certonly --webroot -w /var/www/your-project-dir -d your-domain.com -d another-domain.com


新方式:

$ sudo certbot –nginx
自动配置Nginx和更新证书。

配置nginx

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
server{
listen 80;
# 如果访问http自动跳转到https
return 302 https://your-domain.com/
}
server {
listen 443;
# 需要多个域名配置的话下面只需要保留一个
listen [::]:443 ssl ipv6only=on;
# server name
server_name your-project-name.com;

root your-project-dir;
index index.html index.htm index.php;

ssl on;
# 注意下面的地址要正确
ssl_certificate /etc/letsencrypt/live/your-domain/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/your-domain/privkey.pem;
ssl_session_timeout 5m;
ssl_protocols SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_ciphers "HIGH:!aNULL:!MD5 or HIGH:!aNULL:!MD5:!3DES";
ssl_prefer_server_ciphers on;
}
}

重启 nginx 服务

sudo service nginx restart

到期自动更新

certbot renew --dry-run

如果正常工作(1.5版本有bug会报错),可以使用

certbot renew

待解决问题

1
2
3
4
5
6
7
8
9
10
11
12
13
14
WARNING: unable to check for updates.
Creating virtual environment...
Traceback (most recent call last):
File "/usr/lib/python3/dist-packages/virtualenv.py", line 2363, in <module>
main()
File "/usr/lib/python3/dist-packages/virtualenv.py", line 719, in main
symlink=options.symlink)
File "/usr/lib/python3/dist-packages/virtualenv.py", line 988, in create_environment
download=download,
File "/usr/lib/python3/dist-packages/virtualenv.py", line 918, in install_wheel
call_subprocess(cmd, show_stdout=False, extra_env=env, stdin=SCRIPT)
File "/usr/lib/python3/dist-packages/virtualenv.py", line 812, in call_subprocess
% (cmd_desc, proc.returncode))
OSError: Command /root/.local/share/letsencrypt/bin/python2.7 - setuptools pkg_resources pip wheel failed with error code 2

有说是pip版本的问题,现在升级到最新版本也无用,正在解决。  (2017年4月6日23:23:36)
临时解决的方式,可以apt安装letscrypt,然后使用letscrypt certonly -w /your-project-dir -d your-domain.com安装证书,然后配置证书。

19 个 JavaScript 常用的简写技术

1.三元操作符

当想写if…else语句时,使用三元操作符来代替。

1
2
3
4
5
6
7
const x = 20;
let answer;
if (x > 10) {
answer = 'is greater';
} else {
answer = 'is lesser';
}

简写:

1
const answer = x > 10 ? 'is greater' : 'is lesser';

也可以嵌套if语句:

1
const big = x > 10 ? " greater 10" : x

2.短路求值简写方式

当给一个变量分配另一个值时,想确定源始值不是null,undefined或空值。可以写撰写一个多重条件的if语句。

1
2
3
if (variable1 !== null || variable1 !== undefined || variable1 !== '') {
let variable2 = variable1;
}

或者可以使用短路求值方法:

1
const variable2 = variable1  || 'new';

上面代码的||表示“或运算”,即如果 variable1 有值,则返回 variable1 ,否则返回事先设定的默认值(上例为 ‘new’)。这种写法会对 variable1 进行一次布尔运算,只有为 true 时,才会返回 variable1 。不相信这个?你可以在浏览器中测试下面的代码。

1
2
3
4
5
6
7
let variable1;
let variable2 = variable1 || '';
console.log(variable2 === ''); // prints true

variable1 = 'foo';
variable2 = variable1 || '';
console.log(variable2); // prints foo

3.声明变量简写方法

1
2
3
let x;
let y;
let z = 3;

简写方法:

1
let x, y, z=3;

4.if存在条件简写方法

1
if (likeJavaScript === true)

简写:

1
if (likeJavaScript)

只有likeJavaScript是真值时,二者语句才相等
如果判断值不是真值,则可以这样:

1
2
3
4
let a;
if ( a !== true ) {
// do something...
}

简写:

1
2
3
4
let a;
if ( !a ) {
// do something...
}

5.JavaScript循环简写方法

1
for (let i = 0; i < allImgs.length; i++)

简写:

1
for (let index in allImgs)

也可以使用Array.forEach:

1
2
3
4
5
6
7
8
function logArrayElements(element, index, array) {
console.log("a[" + index + "] = " + element);
}
[2, 5, 9].forEach(logArrayElements);
// logs:
// a[0] = 2
// a[1] = 5
// a[2] = 9

6.短路评价

给一个变量分配的值是通过判断其值是否为null或undefined,则可以:

1
2
3
4
5
6
let dbHost;
if (process.env.DB_HOST) {
dbHost = process.env.DB_HOST;
} else {
dbHost = 'localhost';
}

简写:

1
const dbHost = process.env.DB_HOST || 'localhost';

7.十进制指数

当需要写数字带有很多零时(如10000000),可以采用指数(1e7)来代替这个数字:

1
for (let i = 0; i < 10000; i++) {}

简写:

1
2
3
4
5
6
7
8
9
for (let i = 0; i < 1e7; i++) {}

// 下面都是返回true
1e0 === 1;
1e1 === 10;
1e2 === 100;
1e3 === 1000;
1e4 === 10000;
1e5 === 100000;

8.对象属性简写

如果属性名与key名相同,则可以采用ES6的方法:

1
const obj = { x:x, y:y };

简写:

1
const obj = { x, y };

9.箭头函数简写

传统函数编写方法很容易让人理解和编写,但是当嵌套在另一个函数中,则这些优势就荡然无存。

1
2
3
4
5
6
7
8
9
10
11
function sayHello(name) {
console.log('Hello', name);
}

setTimeout(function() {
console.log('Loaded')
}, 2000);

list.forEach(function(item) {
console.log(item);
});

简写:

1
2
3
4
5
sayHello = name => console.log('Hello', name);

setTimeout(() => console.log('Loaded'), 2000);

list.forEach(item => console.log(item));

10.隐式返回值简写

经常使用return语句来返回函数最终结果,一个单独语句的箭头函数能隐式返回其值(函数必须省略{}为了省略return关键字)

为返回多行语句(例如对象字面表达式),则需要使用()包围函数体。

1
2
3
4
5
6
7
function calcCircumference(diameter) {
return Math.PI * diameter
}

var func = function func() {
return { foo: 1 };
};

简写:

1
2
3
4
5
calcCircumference = diameter => (
Math.PI * diameter;
)

var func = () => ({ foo: 1 });

11.默认参数值

为了给函数中参数传递默认值,通常使用if语句来编写,但是使用ES6定义默认值,则会很简洁:

1
2
3
4
5
6
7
function volume(l, w, h) {
if (w === undefined)
w = 3;
if (h === undefined)
h = 4;
return l * w * h;
}

简写:

1
2
3
volume = (l, w = 3, h = 4 ) => (l * w * h);

volume(2) //output: 24

12.模板字符串

传统的JavaScript语言,输出模板通常是这样写的。

1
2
3
const welcome = 'You have logged in as ' + first + ' ' + last + '.'

const db = 'http://' + host + ':' + port + '/' + database;

ES6可以使用反引号和${}简写:

1
2
3
const welcome = `You have logged in as ${first} ${last}`;

const db = `http://${host}:${port}/${database}`;

13.解构赋值简写方法

在web框架中,经常需要从组件和API之间来回传递数组或对象字面形式的数据,然后需要解构它

1
2
3
4
5
6
7
8
9
const observable = require('mobx/observable');
const action = require('mobx/action');
const runInAction = require('mobx/runInAction');

const store = this.props.store;
const form = this.props.form;
const loading = this.props.loading;
const errors = this.props.errors;
const entity = this.props.entity;

简写:

1
2
3
4
5
6
7
import { observable, action, runInAction } from 'mobx';

const { store, form, loading, errors, entity } = this.props;
也可以分配变量名:

const { store, form, loading, errors, entity:contact } = this.props;
//最后一个变量名为contact

14.多行字符串简写

需要输出多行字符串,需要使用+来拼接:

1
2
3
4
5
6
const lorem = 'Lorem ipsum dolor sit amet, consectetur\n\t'
+ 'adipisicing elit, sed do eiusmod tempor incididunt\n\t'
+ 'ut labore et dolore magna aliqua. Ut enim ad minim\n\t'
+ 'veniam, quis nostrud exercitation ullamco laboris\n\t'
+ 'nisi ut aliquip ex ea commodo consequat. Duis aute\n\t'
+ 'irure dolor in reprehenderit in voluptate velit esse.\n\t'

使用反引号,则可以达到简写作用:

1
2
3
4
5
6
const lorem = `Lorem ipsum dolor sit amet, consectetur
adipisicing elit, sed do eiusmod tempor incididunt
ut labore et dolore magna aliqua. Ut enim ad minim
veniam, quis nostrud exercitation ullamco laboris
nisi ut aliquip ex ea commodo consequat. Duis aute
irure dolor in reprehenderit in voluptate velit esse.`

15.扩展运算符简写

扩展运算符有几种用例让JavaScript代码更加有效使用,可以用来代替某个数组函数。

1
2
3
4
5
6
7
// joining arrays
const odd = [1, 3, 5];
const nums = [2 ,4 , 6].concat(odd);

// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = arr.slice()

简写:

1
2
3
4
5
6
7
8
// joining arrays
const odd = [1, 3, 5 ];
const nums = [2 ,4 , 6, ...odd];
console.log(nums); // [ 2, 4, 6, 1, 3, 5 ]

// cloning arrays
const arr = [1, 2, 3, 4];
const arr2 = [...arr];

不像concat()函数,可以使用扩展运算符来在一个数组中任意处插入另一个数组。

1
2
const odd = [1, 3, 5 ];
const nums = [2, ...odd, 4 , 6];

也可以使用扩展运算符解构:

1
2
3
4
const { a, b, ...z } = { a: 1, b: 2, c: 3, d: 4 };
console.log(a) // 1
console.log(b) // 2
console.log(z) // { c: 3, d: 4 }

16.强制参数简写

JavaScript中如果没有向函数参数传递值,则参数为undefined。为了增强参数赋值,可以使用if语句来抛出异常,或使用强制参数简写方法。

1
2
3
4
5
6
function foo(bar) {
if(bar === undefined) {
throw new Error('Missing parameter!');
}
return bar;
}

简写:

1
2
3
4
5
6
7
mandatory = () => {
throw new Error('Missing parameter!');
}

foo = (bar = mandatory()) => {
return bar;
}

17.Array.find简写

想从数组中查找某个值,则需要循环。在ES6中,find()函数能实现同样效果。

1
2
3
4
5
6
7
8
9
10
11
12
13
const pets = [
{ type: 'Dog', name: 'Max'},
{ type: 'Cat', name: 'Karl'},
{ type: 'Dog', name: 'Tommy'},
]

function findDog(name) {
for(let i = 0; i<pets.length; ++i) {
if(pets[i].type === 'Dog' && pets[i].name === name) {
return pets[i];
}
}
}

简写:

1
2
pet = pets.find(pet => pet.type ==='Dog' && pet.name === 'Tommy');
console.log(pet); // { type: 'Dog', name: 'Tommy' }

18.Object[key]简写

考虑一个验证函数

1
2
3
4
5
6
7
8
9
function validate(values) {
if(!values.first)
return false;
if(!values.last)
return false;
return true;
}

console.log(validate({first:'Bruce',last:'Wayne'})); // true

假设当需要不同域和规则来验证,能否编写一个通用函数在运行时确认?

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
// 对象验证规则
const schema = {
first: {
required:true
},
last: {
required:true
}
}

// 通用验证函数
const validate = (schema, values) => {
for(field in schema) {
if(schema[field].required) {
if(!values[field]) {
return false;
}
}
}
return true;
}


console.log(validate(schema, {first:'Bruce'})); // false
console.log(validate(schema, {first:'Bruce',last:'Wayne'})); // true

现在可以有适用于各种情况的验证函数,不需要为了每个而编写自定义验证函数了

19.双重非位运算简写

有一个有效用例用于双重非运算操作符。可以用来代替Math.floor(),其优势在于运行更快,可以阅读此文章了解更多位运算。

1
Math.floor(4.9) === 4  //true

简写

1
~~4.9 === 4  //true

JS中非严格比较操作符的类型转换逻辑

在 JavaScript 中有六种数据会自动转化为布尔型

1
2
3
4
5
6
7
8
if ( !undefined
&& !null
&& !0
&& !NaN
&& !''
) {
console.log('bool true');
} // bool true

在ECMA规范中非严格操作符(==)是会强制类型转换的,这点和上面的六种转换逻辑还不一样,也就是说当遇到非严格操作符的时候,undefined不会转化为false然后再与后面对比。

1
console.log( undefined == false) // false

规范有点绕,其实特别简单——

如果要比较 x==y,有下面这几种情况

如果 x 和 y 的类型相同,那就直接比较值,这个相当于转化为严格等于

1
console.log( 1 == 2) //false

如果 x 和 y 要么是 null 要么是 undefined,则返回 true

1
console.log( undefined == null ) //true

如果 x 和 y 一个是 string 类型,一个是 number 类型,那么 string 类型的要转化为 number 类型。

1
console.log( '1' == 1, '1a' == 1)  //true false 

如果 x 和 y 其中一个是 bool 值,那么这个 bool 值要转化为 number 类型

1
console.log(1 == true, 0 == false) // true true

如果 x 和 y 其中一个是 Object,那么 Object 要转化为原始类型。

1
console.log(['1'] == 1)//true

不属于以上情况,返回 false

那么问题来了,console.log( [] == false )的结果是什么?

正确答案为 true,但是 console.log( !![] == true) 也是返回 true,因为按照优先级,这个是需要先执行 !![],也就是是 !!(ToBoolean([]))

更有趣的一点,你可以在浏览器中运行

1
console.log(Array.isArray(Array.prototype))

上面的转化逻辑是ECMA的标准的,其实更简单的理解就是:

如果都是原始类型,那么都转化为数值类型;如果是对象,那么就转化为原始类型再进行比较。undefined和null与其他类型的值比较时,结果都为false,它们互相比较时结果为true。

使用公私钥登录远程服务器

使用公私钥登录远程服务器

本机生成公私钥

1
2
3
4
5
6
7
8
9
10
11
12
13
ssh-keygen -t rsa 
# 一直回车默认即可
Generating public/private rsa key pair.
# Key存放路径
Enter file in which to save the key (/lishude/.ssh/id_rsa):
# 输入密码短语(留空则直接回车)
Enter passphrase (empty for no passphrase):
# 重复密码短语
Enter same passphrase again:
Your identification has been saved in /lishude/.ssh/id_rsa.
Your public key has been saved in /lishude/.ssh/id_rsa.pub.
The key fingerprint is:
blah...

拷贝公钥到远程服务器

1
2
#复制公钥到无密码登录的服务器上,22端口改变可以使用下面的命令
ssh-copy-id -i ~/.ssh/id_rsa.pub username@remote_server

修改远程服务器SSH配置文件

1
2
3
4
5
6
7
8
9
10
vim /etc/ssh/sshd_config
#禁用密码验证
PasswordAuthentication no
#启用密钥验证
RSAAuthentication yes
PubkeyAuthentication yes
#指定公钥数据库文件
AuthorsizedKeysFile ~/.ssh/authorized_keys
#重启SSH服务
service ssh restart

注意:AuthorsizedKeysFile ~/.ssh/authorized_keys,如果存在多用户,最好使用绝对路径,因为如果修改文件的是当前环境是root用户,~代表/home/root,否则不同的用户会存在不用密钥也可以登录。

补充一点,当我们使用 xshell 工具的时候,导入的文件是私钥文件,一般名称为 id_rsa,如果导入公钥文件会报错

image

我在阿里云上使用的时候,如果电脑不在身边,其实也可以登录,阿里云默认的Ubuntu真是神奇,比root用户还要高一级的 bot root 用户,当然在系统中看不到,这个可以用来在阿里云后台更改root用户的密码!呃,如果电脑出故障了,如果重置密码,那么公私钥登录的方式也会被暂停,需要重新编辑ssh配置文件..

前段时间爆出xshell存在后门,后来我就不用xshell了,windows下我就直接用git shell登录,虽然麻烦一点,但是安全了很多。

初始化 Ubuntu Server 清单

说明

学习Linux最好的方式就是使用发行版的操作系统,Ubuntu是我第一个接触的系统,当然也是广泛被推荐给新手学习的第一个操作系统。

下载安装

百度搜索下载即可,windows下我们需要先安装虚拟机,我用的VMware 12,这个挺好用的,中文界面,功能强大,不过不好的地方就是需要花钱。不过有些事情你懂的。Ubuntu一般都是下载图形界面的桌面版本,其实我感觉学习Linux要有feel的话,当然还是要用全字符界面的Server服务器版本咯。下载安装比较简单,不提。

我们安装好了虚拟机,其实在虚拟机中操作不太好,我们最好在桌面上下载一个可以ssh软件来连接虚拟机。另外我推荐大家使用一个xshell软件。

新建环境

这个也不难,打开vmware,新建一个虚拟机,选择Ubuntu Server的镜像,一步一步的来。基本上我们不用管,需要留意的是,因为vmware简易安装使用的美国的软件源,安装过程中会很慢,这个我们稍等一下就好。

进入系统

更新软件源

sudo apt-get update
一般会很慢,因为是用的美国的软件源。等一会,然后我们安装vim文本编辑器来修改软件源。

安装vim

是的,vmware简易安装模式没有文本编辑器,所以我们要手动下载一个文本编辑器。这里推荐安装vim。

sudo apt-get install vim

同样会很慢,我们稍等一会就好了。

修改源

1
2
cd /etc/apt/
sudo vim source.list

我们把所有的us换成cn就好了。

如果不用vim修改源的话,可以使用sed命令。

sudo sed -i 's/us/cn/g' /etc/apt/sources.list

安装ssh服务

这里是个大坑,因为我学linux的时候死活在宿主机上用xshell连接不上虚拟机。原因现在看来很简单,就是server没有安装ssh服务,所以我们用xshell连接虚拟机的22端口的时候是被拒绝。

安装ssh server
sudo apt-get install openssh-server
启动ssh server
sudo /etc/init.d/ssh start
确定ssh服务启动
ps -e | grep ssh
设定服务端口
sudo vim /etc/ssh/sshd_config
sudo /etc/init.d/ssh restart

一般情况下不需要检查ssh服务是否启动成功。

用xshell连接虚拟机

在虚拟机中输入 ifconfig 找到 inet ip,然后再 xshell 连接这个 ip地址 就可以了。

LNMP环境搭建最佳实践

laravel+LNMP配置最佳实践

更新软件源

sudo apt-get update

解决语言问题冲突

1
2
3
4
sudo apt-get install -y language-pack-en-base
locale-gen en_US.UTF-8
export LANG=en_US.UTF-8
export LC_ALL=en_US.UTF-8

安装所有依赖

sudo apt install git vim php7.1-mysql php7.1-fpm php7.1-curl php7.1-xml php7.1-mcrypt php7.1-json php7.1-gd php7.1-mbstring php7.1-curl php7.1-zip php mysql-server nginx -y

安装PHP7.1需要PPA第三方源支持,具体参考这篇文章

安装Git和Vim

sudo apt-get install git vim -y

安装 php7

sudo apt-get install php -y

查看php版本:php -v

安装 php7-lib

sudo apt-get install php7.1-mysql php7.1-fpm php7.1-curl php7.1-xml php7.1-mcrypt php7.1-json php7.1-gd php7.1-mbstring php7.1-curl php7.1-zip -y

注意: php-zip 包,composer特别需要!

安装 mysql

sudo apt-get install mysql-server -y
查看mysql版本:mysql --verison

新建数据库

create database dbname default charset utf8mb4 collate utf8mb4_unicode_ci

更新数据库

1
2
sudo mysql_upgrade -u root -p
service mysql restart

安装 Nginx

sudo apt-get install nginx -y
查看nginx版本:nginx -v

配置 PHP

php-fpm配置

打开并编辑: /etc/php/7.1/fpm/pool.d/www.conf

1
2
3
listen.own = <nginx.user>
listen.group = <nginx.group>
listen = /var/run/php/php7.1-fpm.sock`

URL安全配置

打开并编辑: /etc/php/7.1/fpm/php.ini

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
/cgi.fix_pathinfo = 0
```

## 配置 Nginx

打开并编辑:` /etc/nginx/sites-available/default`

```conf
server {
listen 80 default_server;
listen [::]:80 default_server ipv6only=on;

root YOUR-PROJECT-DIR/public;
index index.html index.php index.htm;

server_name YOUR DOMAIN OR IP;

location / {
try_files $uri $uri/ /index.php?$query_string;
}

location ~ \.php$ {
try_files $uri /index.php =404;
fastcgi_split_path_info ^(.+\.php)(/.+)$;
fastcgi_pass unix:/var/run/php/php7.1-fpm.sock;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
include fastcgi_params;
}
}

配置gzip

打开并编辑:/etc/nginx/nginx.conf

1
2
3
4
5
6
7
8
9
10
gzip on;
gzip_disable "msie6";
gzip_vary on;
gzip_proxied any;
gzip_comp_level 5;
gzip_min_length 256;
gzip_buffers 16 8k;
gzip_http_version 1.1;
gzip_types text/plain text/css application/json application/x-javascript
text/xml application/xml application/xml+rss text/javascript;

同样的,在此文件最上面编辑 user

1
user user group

建议就使用当前用户

重启服务

1
2
sudo service nginx restart
sudo service php7.1-fpm restart

Composer

安装

1
2
sudo wget https://dl.laravel-china.org/composer.phar -O /usr/local/bin/composer
sudo chmod a+x /usr/local/bin/composer

注意:因为Composer不推荐使用root用户进行安装依赖(安全问题),所以最好把网站目录放在当前用户目录之下。

国内Composer镜像

1
composer config -g repo.packagist composer https://packagist.laravel-china.org

为文件目录赋权

为访问网站用户赋权,如果nginx设置的就是当前用户就不需要这一步。

sudo chown -R <nginx-user:nginx-group> YOUR-PROJECT-DIR

为storage赋予写权限,但这一步,我建议在开发环境就设置并提交到git中

sudo chmod -R 775 YOUR-PROJECT/storage

所以这两步骤都可以省略!最好都省略掉,如果不省略掉就会很麻烦的 git pull 之后还得更新文件权限和所属关系。

更多内容可以参见我的 nginx 分类中文章。