Zhao Li https://livc.io 2018-10-25T15:16:19+00:00 livc@outlook.com Nginx 反向代理 Https https://livc.io/blog/233 2018-10-25T00:00:00+00:00 Zhao Li https://livc.io/blog/233 这种情况实际的后端服务器直接 http 启动,证书配置在 Nginx 上。

server
	{
    	listen 80;
    	server_name domain.com;
    	rewrite ^(.*)$ https://domain.com$1 permanent;
    }

server
    {
        listen 443 ssl http2;
        server_name domain.com ;

        ssl on;
        ssl_certificate path;
        ssl_certificate_key path;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "YOUR";
        ssl_session_cache builtin:1000 shared:SSL:10m;
        ssl_dhparam path;
        location /
        {
        	# 注意这里是http
            proxy_pass http://127.0.0.1:8081;
            proxy_set_header Host domain.com;
            proxy_set_header X-Forwarded-Proto https;
        }
    }

]]>
[转]是枝裕和在树木希林葬礼上的悼词 https://livc.io/blog/232 2018-10-10T00:00:00+00:00 Zhao Li https://livc.io/blog/232 本文转载自http://xiabing.blog.caixin.com/archives/189609

根据辞典,悼词是哀悼逝者的文字,告别式按字面的理解是与逝者道别的场所。希林女士罹患绝症,我已经对这一天有了心理准备,但还是没想到这一天会如此突然地到来,无法立刻接受这样的事实。多年前我失去了母亲,现在我陷入第二次丧母的悲痛深渊之中难以自拔。对我来说,您就像我的另一位母亲一样。

我和希林女士第一次见面是2007年的事,和她的交往时间,不过十年有余。所以,我能够谈及的希林女士的,仅仅是她漫长艺术职业生涯的最后篇章。我一直不敢认为自己有致悼词的资格,踌躇再三,还是决定接受这个任务。

现在代替我诵读悼词的桥爪功先生,和希林女士是文学座剧团研究所的同窗,是以“桥爪君”“chaki”互称的老朋友。我曾经邀请二位在我的作品里扮演一对夫妻,拍摄过程中,我们一同在鹿儿岛共进晚餐,并排坐在餐馆的柜台前边吃天妇罗,边听你们像说对口相声一样斗嘴,你们谈到离婚赔偿费和整容(希林女士喜欢的话题)引来笑声,间或谈到表演的课题,谈锋甚健。我从交谈中可以体会到你们在超过半个世纪的岁月里积淀出的对彼此人格和艺术的相互尊敬,感到无比羡慕,暗想哪天我也能和你们以这样平等的关系互动。这样的愿望最终未能实现,因而我请桥爪先生代为诵读这篇悼词,这样我能借此产生一种参与了你们亲切对话的错觉。

希林女士与我有将近20岁的年龄差,不揣冒昧地说,我们确实是气味相投。我们的相遇是机缘巧合,2007年,我准备拍摄以家母为原型的电影《步履不停》,在前一年,希林女士失去了事业上的盟友久世光彦。有时我会产生这样的念头:如果久世先生还健在的话,希林女士还会以一个作品主创人员的身份选择我,并且给我许多指导么?想到您在久世先生曾经希望拍成电视剧的《东京塔》电影版中扮演母亲,不由得感到您在继续一个未竟的梦想。当然,我从未觉得希林女士把我当作另一个久世先生,而是认为,我继承了您和久世先生之间一度中断的缘分。(译者注:东京电视台著名导演久世光彦,是树木希林早期的贵人和合作伙伴,由于树木希林不顾文艺界潜规则,公开揭露久世与一名新人女演员的不伦之恋,两人翻脸,到晚年才和解)。

我不太清楚希林女士对我青眼相加的理由,或许理由之一是:我从拍摄电视片起家,在电影界没有可以仰仗的师父和前辈,您同情我这个形单影只的年轻人,对我特别关照。所以每次电影公映时,您不给我而是给制片人打电话,询问上座率,得到回答后说“那下次又可以拍新戏了,太棒了!太棒了!”然后才放下悬着的心。一直到我最新的影片,希林女士每次必打这样的电话,仿佛是慈母牵挂着不成器的儿子。您经常带我外出用餐,享受各种各样的佳肴。一进店,您就对主厨说:“想吃套餐的每道菜,但是量要减半,”在寿司店,则跟师傅出难题:“什么都可以,凑数的菜码就不要了,好吃的样数只要给我一半。”说起森繁久弥、渥美清、久世光彦,您会熟练地模仿着他们的动作和说话口吻。有幸独享这些秘闻,我只顾点头称是。和您离开餐馆后,您笑着故意捉弄我“你猜刚才多少钱?”“很便宜对吧?所以咱们白天去,晚上就贵喽!”你流露的平民本色,也充满魅力。

我和您一起度过的时光,实在是非常快乐。作为一个儿子,未能在人生中和生母相处更久,也许是我试图将那种悔恨、想重新生活一遍的渴望、未能实现的心愿,通过和希林女士的相处得到补偿。我从未说出这样的想法,但是善解人意的希林女士一定早就察觉了。通过请希林女士扮演我的电影中的母亲角色,和希林女士一同进餐、谈天,我渐渐平复了丧母之痛。而就在这个时候,我失去了另一位母亲,又要平复另一层丧母之痛。

刚才我冒昧地说过,我与希林女士气味相投。当然这也不意味着我和她的价值观完全一致。一次,谈论起我喜欢的剧作家,当我提到向田邦子的名字时,您很罕见地露出严肃的表情,从正面盯着我的脸,问:“你认为她好在哪里?”希林女士追问:“嗯?好在哪里?”“嗯?为什么?”的时候,能不能拿出有说服力的论据,决定着希林女士对那个人的评价。我一边流着冷汗,一边谈到向田剧本的魅力,您说:“那是她不与我们合作以后的作品呢。”这句话里同时有着释然和寂寞两种情绪的奇妙交响。希林女士虽然不喜欢向田的风格,还是为和久世先生一起在电视的世界创造辉煌感到自豪。我也可以想象,患病后的向田女士转向写作严肃的电视剧和文章以后,您对她是怎样的看法。哪怕电视和广告播放之后就会消失殆尽,也要追求品味,和您不拘一格潇洒的人生哲学,肯定是有共鸣的。2005年您患了和向田女士一样的病以后,将工作的重心转到能流传后世的电影,从扮演小角色给人留下独特印象,转变到担任决定作品成败的主角。我从未向您询问过为何有这样的改变。但是我却像配合着您的改变一样请你拍片。有时我也会担心,因为遇到我和我的作品,您的风格改变了,曾经是您魅力一部分的轻松愉悦感是不是会流逝了?这些都被证明是多余的担忧。您一边说,拍电视连续剧体力跟不上,一边连续出现在午后综艺节目和焰火大会的直播节目里,问您原因,您说,想测试自己作为一个艺人,在今天的时代有多少意义和价值。您的行动力、勇于尝试的精神,在电视出身的我眼里,充满了魅力。因此,当听到报道您的讣告,各色人等称您“女明星”“超级女星”的时候,感到一丝不自在,甚至我感觉这是对您的捧杀。希林女士在天之灵也一定有同感吧?作为演员,您常说的自我评价是“我这个人不中用”“我没什么本事”,尤其是拒绝片约时,经常这样说。拍摄《比海更深》的时候,您拿着已经接受了的剧本来到我的事务所,对一再坚持己见的我反复说着这句话:“做不来”“不管怎样”“做不来”。我们在桌边花了一个小时争论,将剧本推来推去。但是开拍后这样的纠结仿佛烟消云散,您为了演好角色全力以赴。在更衣室换好服装,端坐在小区楼房的窗边,认真地熟背台词,就像一个出道不久的新人一样勤勤恳恳的背影,我至今难以忘怀。

去年春天我请您出演《小偷家族》的时候,尽管剧本还没写好,您爽快地接受了邀请。我做好了您半途拒绝的思想准备,同时对您的态度感到欣慰又有些不可思议。杀青的3月30日您来到事务所,给我看了您的全身扫描片,显示癌症转移的小黑点,布满了全身的骨骼。医生已经告诉您,还剩下不到一年的寿命,您告诉我:“这是我最后一次参演你的电影。”我知道您来日无多,但是那一天还是这样快就到了,我不知该如何表述自己的心情。我后悔让您演了一个死在电影中的角色,但这也许是天意,要我与您相遇、与您合作、虽有些轻率,却在电影里先让我与您道别。希林女士莫非也是因为如此才接受了这个角色?去年十二月,拍摄刚刚开始的时候,希林女士就对来采访的记者说:“这是最后一次与是枝导演合作。”

影片拍竣,六月八日上映,希林女士大约是希望我和她的关系到此为止吧。您抓着我的手臂,拄着拐杖走到台上,那天道别的时候,您对我说:

“你就把老婆子的事忘了吧!你要把你的时间,用在年轻人身上!我就不再和你见面了。”

您说到做到,从第二天起无论我怎么邀请您喝茶,您都坚决地拒绝。我感到困惑,是因为我没有像您那样做好思想准备。您骨折住院时我知道无法见到您,就写了一封信投进府上的邮箱。信上写着没有能当面说出的对您的感激,我对自己一路来的自我中心,感到万分惭愧。以后,没过多久接到了您驾鹤西去的消息。

接到讣告后,我来到您灵前守夜。时隔三个月见到的您,依然那么美,美得端庄而大气。看到您的那一刻,我终于悟出,您不愿与我相会,是为我着想,想要减轻我失去您的悲伤。我就像《小偷家族》当中您那没有血缘关系的孙女所做的那样,用指尖触摸了您的头发和前额,然后把您在电影中所说的话,又说给了灵柩中的您。

我总觉得人往生之后,会存在于万物。我失去母亲之后,反而觉得母亲存在于周遭的一切事物中,会在街头擦肩而过,会在陌生人中忽然发现她的身影。这样想着,就慢慢超越了悲痛。现在,您的家人失去了妻子、母亲、姐姐、祖母,遗属的哀痛是无法估量的。但是今天的别离,意味着您将超越肉体,活在世间万物之中。希望总有一天,活着的人会接受这样的现实。

请允许我谈一点私事。希林女士,您逝世的9月15日,也是我母亲过世的日子。和母亲永别之日,竟然也是与另一个像母亲一样的人永别的日子,这样的巧合使我悲痛欲绝,难以释怀。也许我不应该把失去母亲与后来与您相遇联系起来,但是千真万确的是因为失去母亲,想把这一切写入作品的时候,刚好遇到希林女士。您挽救了天涯孤独的我,关爱着我,因此,我作为活着的人,要像当年一样,将这样的悲痛升华成作品。我曾与您一起走过人生的某一阶段,这是我的责任,是我对您恩情的回报。

就像我追逐着您远去的背影一样,我向着灵柩中的您再一次重复我道别的话,以此结束我的悼词。

希林女士,遇见您,真是太感谢了。再见。

]]>
我在 GDD 偶遇樊麾 https://livc.io/blog/231 2018-09-20T00:00:00+00:00 Zhao Li https://livc.io/blog/231 来到上海的第二年,也是第二次参加谷歌开发者大会(GDD)。在排队 checkin 时偶然望到一个人特别像樊麾,问了一下同行的目前在 Google 实习的学长,发现真的是他。不过心想为什么他和我们一起排队领 Guest 的 Badge 而不是 Googler 的呢?排了好久队,发现貌似大家都没有认出樊麾,checkin 后我主动去打招呼:

“你好,你是樊麾吗?”

“是我。”

“真的吗?”

“没错,是我,活的!”,说这句话时樊麾瞪大了眼睛……

之后简单聊了几句,我说我看过那部 AlphaGo,他问我是不是做 ML 的,我说目前在上海上学做 NLP 相关的,然后我就去会场了,他和朋友继续在大厅中聊天,期间还是没有人认出他。

见到樊麾时非常激动,我想主要来自于《AlphaGo》这部纪录片对我的影响。不知道是这部片拍的好,还是因为这个 project 真的让人振奋,我在看过之后感到异常兴奋和鼓舞,感慨人类的伟大智慧。而这部纪录片的主人公就是樊麾,一个非常有趣的科技男形象。

今年的 GDD 秩序不如去年,主会场比较小导致许多人只能在分会场看直播,产品体验区的展位也少了许多,当然小礼物也对应少了不少。午餐从去年的中西自助变成了盒饭,我的蔬菜里面还有一条虫子,我们都在开玩笑能不能拿这个虫子换一个 offer……

上午有一场 Demo Day 的活动,有一些 start-up 会进行路演。这个我原本很想去看的,但因为下午有课,时间来不及,就没有去看。中午又来了几个学长,有一位和我共同选了下午的密码学课,结果就是最后我俩都逃掉了。

我观察到一个非常有意思的现象:Google 在今年 GDD 的品牌宣传上不知是有意还是无意的强调了“谷歌”这两个汉字,比如说贴纸:

在我的印象中,去年的贴纸 Google 后面是没有中文汉字的,贴纸上的“谷歌”两个汉字让我觉得不是很酷,所以没有把它贴在电脑上。

另外可以对比一下今年送的书包和去年我在与李飞飞闭门会议上得到的书包,这两个包除了颜色,样式一模一样:

Google 可能真的要回到中国了,只是不知道它是否还记得那句经典的信条。

]]>
Dropbox + VSCode: index file changed https://livc.io/blog/230 2018-08-22T00:00:00+00:00 Zhao Li https://livc.io/blog/230 在两台机器上同时用 VSC 打开一个 git 中的文件时,会不断弹出 index file changed 的提示,这是因为 VSC 会自动 autofetch 来检查整个仓库,这个过程会改动 .git/index 这个文件,解决方法有两个:

  1. 更新使两台机器的 git 版本一致后正常,推测 git fetch 后会将版本信息保存到 index 中。
  2. 或者直接禁用 autofetch:"git.autofetch": false

Reference

]]>
写在 hackShanghai 之后 https://livc.io/blog/229 2018-07-25T00:00:00+00:00 Zhao Li https://livc.io/blog/229 上周末参加了 hack.init() 举办的 hackShanghai,主办方是一群高中生,能把这么大的比赛办起来确实非常厉害。我们做了一个优惠券交易的 dapp,是一个学弟的 idea,这个过程还是很有感慨。

最开始我们都觉得这个场景太小,而且不太现实,当然学弟自己也没把这个事想清楚,后来讨论着讨论着,把场景、需求、痛点和解决方案一整理,居然自己也开始觉得有一点靠谱了,认为这个是行得通可以做下去的。

从执行者角度来看,很多时候接收到的一个决策可能都不是最优的,我想起阿里合伙人彭蕾曾经说过一句话,“无论马云的决定是什么,我的任务都只有一个——帮助这个决定成为最正确的决定。”而这个过程就是需要大家不断地耐心讨论和完善,而不能说一开始觉得它不靠谱,就放弃或者排斥它了。

最近头条的一个产品失败,有员工在内网问责和复盘,被查水表和强制离职了,其实这就是没有想明白自己的位置。很多时候公司高层的决策和战略不需要让每个员工知晓,而员工说白了就是个打工的,需要做的只是让这个看似不好的决策成为最好的,而对公司的建议和上层的决策要掌握好尺度。

还有一个有意思的事是,根据我们找到的一项数据,在 2010 年美国消费者使用的优惠券的数量只有总发放数量的 1%,这个数据低得超出了我的想象,因此相信数据而不要相信直觉。

我参加的组别是高年级大学生,还有面向低年级和高中生的组别,这个组别的前四名中有三支团队的高中生都能训练一个简单的深度学习模型并找到可应用的场景,因此觉得区块链这波风口过去可能还需要一段时间,最起码要等到高中生也开始接触区块链吧,哈哈。

最近在想的另外一个事是,微型博客的存在让人们把原来写在博客上的文字发到了微博上,然而微博其实并不是一个很好的归档平台,发完就很容易忘掉,所以上面这些文字完全可以发成一个长微博,但我还是选择了博客。

]]>
共识算法 PBFT https://livc.io/blog/228 2018-07-18T00:00:00+00:00 Zhao Li https://livc.io/blog/228 共识算法是分布式系统中一个很重要的概念,多个节点协同工作,如何就某个请求达成一致是一个很复杂的事。PBFT 全称 Practical Byzantine-Fault-Tolerant,是 BFT(拜占庭容错)算法的一种。

在分布式系统中主要有两种故障类型:一是系统的延迟、宕机等非人为错误,称为非拜占庭错误,另一种是人为的作恶比如恶意攻击,这在区块链系统中讨论较多,称为拜占庭式错误,PBFT 属于后者。关于拜占庭容错的理论可以看下其他文章,这篇文章主要描述算法。

PBFT 的相关论文比较多,https://www.microsoft.com/en-us/research/publication/practical-byzantine-fault-tolerance-proactive-recovery/ 这篇比较容易理解,同时有很多开源的实现,https://github.com/gdanezis/pybft 比较完整,符号和 paper 中一致,就是没有注释,不是很容易完全看懂。

Overview

客户端发送请求给副本(去执行一些操作),BFT 保证所有正常的副本以相同的顺序执行相同的操作,如果客户端收到来自 f+1个节点的相同的响应消息,则共识完成,执行请求;由于这 f+1 个中至少一个是正常的副本,因此可以保证结果是正确的,但是难处在于在一个分布式系统中,如何确保正常的副本以相同的顺序执行相同的请求。

PBFT 使用 primary-backup 和 quorum replication 技术去为请求排序。

primary-backup

在一个 view 中,有一个副本是主节点(primary),其他副本是备份节点(backups)。主节点接收客户端的请求并给它安排一个可用的序号(sequence number),然后发给备份节点。主节点可能坏掉,比如为不同的请求安排了相同的序号、停止安排序号、序号不连续等等。备份节点会检查序号,并且设置了超时机制以防主节点挂掉。如果主节点挂掉后,view 会切换并且选择新的主节点。

quorum

quorum 有两个重要的属性:

  • Intersection:任意两个 quorum 至少有一个公共的正确副本。
  • Availability:总有一个没有出错副本的 quorum。

副本将信息写入 quorum 后得到 quorum certificate,这些证书是信息已经被可靠存储的证明。此外 weak certificates 代表至少 f+1 个不同的副本存储信息,这样能保证至少有一个正确的副本存储了信息。

副本的集合用 R 表示,{0,…, R -1}, R =3f+1,f 是最大故障节点数。
主节点为 p=v mod R
其中 v 是视图号(view number),是连续增加的,这样保证主节点在{0,…, R -1}内。

定义集合 quorum 里至少有 2f+1 个副本。

客户端

客户端 c 通过广播 <REQUEST,o,t,c> 发送包括操作 o 的请求给副本,其中 t 是时间戳。

当请求最后达成共识后,副本会回复给客户端 <REPLY,v,t,c,i,r> 其中 v 是当前视图号,t 是对应请求的时间戳,i 是副本号, r 是请求操作的执行结果。

客户端收到来自 f+1 个不同副本(具有相同 t 和 r)的回复后(weak certificate),会接受结果 r。由于最多有 f 个副本是坏的,那么这就保证结果是有效的,称之为 reply certificate。

若客户端未在一定时间内收到 reply certificate,它会再次发送请求,如果请求已经被处理了,副本会再次发送回复,因此副本需要记住它对每一个客户端回复的上一个消息。如果主节点没有为请求安排合适的序号,它就会被其他节点怀疑坏掉,足够多时会造成主节点更换(view change)。

对于客户端数量带来的可扩展性,可以通过限制活跃客户端数量来解决。

示范

我们使用三段协议去自动广播请求给副本:pre-prepare,prepare,commit。下图是没有故障节点时的算法总览:

pre-prepare

主节点 p (0 号副本)收到客户端请求 m (m=<REQUEST,o,t,c> )后,分配序号为 n,广播 pre-prepare 信息给备份节点,格式为 <PRE-PREPARE,v,n,D(m)>,其中 v 是视图号,D(m) 是 m 的 digest。

n 要在低水位 h 和高水位 H 之间,保证垃圾回收机制和防止出错的主节点随意选择序号。

如果其他备份节点已经收到了包含 v 和 n 但不同 digest 的PRE-PREPARE,那么它就不会接受(not accept)。

prepare

备份节点进入 prepare 节点,向其他副本广播 <PREPARE,v,n,D(m),i>,同时会将 PRE-PREPARE 和 PREPARE 的信息写入日志。

每个副本收到 2f 个一致的 PREPARE后会得到 prepared certificate,证明了这个 quorum 一致同意视图 v 内 m 的序号为 n。

commit

副本 i 广播 <COMMIT,v,n,i> 来宣布自己已经拥有了 prepared certificate,当副本收到 2f+1 个来自不同副本(包括自己)的 COMMIT 后(n, v 相同),获得 committed certificate。

每个副本按照客户端请求的顺序执行请求,然后回复客户端。

垃圾回收

已经执行过的请求的相关日志应该被删除,但是其中包含的 prepared certificate 可能在后面被使用,所以应该什么时候删除呢?

每个副本在执行请求后可以广播全网说可以删掉 log 了,但是每个请求后都发成本比较高,因此设计 checkpoint period K,每 K 个请求广播一次,这个 checkpoint 称为 stable checkpoint。

副本 i 到达 checkpoints 时向其他副本广播 <CHECKPOINT,n,d,i>,其中 n 是上一请求序号,d 是 digest,其他副本收到 2f+1 (包括自身)个 CHECKPOINT 消息后,会删掉所有序号小于等于 n 的 log 和之前的checkpoints。

但在实际的系统中,每个副本都不是同步的,所以高低水位限制了什么样的消息能够添加到 log 中。高水位 H=h+L,其中 L 是 log size,低水位 h 是上一个 stable checkpoint 的序号。高水位一般是 K 的倍数,而且比较小,比如 2 倍,因此如果有的副本执行的比较快的话,需要等一等其他副本,这个区间足够了。

视图切换

view change 协议主要发生在主节点故障时,新的 view 如何保持上一 view 的状态,以及如何处理未完成的请求。

数据结构

副本需要用两个集合 P 和 Q 记录之前 view 里的信息,系统正常时这两个集合是空的。

副本 i 的集合 P 存储了之前 view 中到达 prepared 状态的请求,数据结构为 <n,d,v> 意为副本 i 收集到 view v 中序号为 n,digest 为 d 的请求的 prepared certificate,并且副本 i 上的下一个 view 中就不能有相同序号的请求。

Q 存储了之前 view 中到达 pre-prepared 状态,<n,d,v> 意为 i 已经 pre-prepare 了一个请求并且在下一 view 中这个请求没有相同序号的 pre-prepare。

View-Change Messages

下图展示了从 v 切换到 v+1 时的 view change 协议。当备份节点 i 怀疑视图 v 下的主节点作恶之后,它会切换到 v+1 中并且广播 <VIEW-CHANGE,v+1,C,P,Q,i>,其中 h 是副本 i 的最新 stable checkpoint,C 是每个 checkpoint <序号, digest> 的集合,P 和 Q 上上一节描述的。

View-Change-Ack Messages

副本收集 VIEW-CHANGE 消息后发送 acknowledgments 以达成切换到 v+1 的共识,<VIEW-CHANGE-ACK,v+1,i,j,d> 其中 i 是发送者的标识,d 是acknowledged VIEW-CHANGE message 的 digest,j 是发送 VIEW-CHANGE 消息的副本。

接下来是 New-View Message Construction 和 New-View Message Processing,属于比较细节的处理,这里不再介绍。

]]>
见字如面(一) https://livc.io/blog/227 2018-06-17T00:00:00+00:00 Zhao Li https://livc.io/blog/227 《见字如面》是最近在看的一个很喜欢的文化类综艺节目,每期邀请嘉宾朗读历史书信。现代社会很多人不读书、不写作,以书信为载体的文字更是很有可能会彻底消失。没人能够阻止时代的发展,但有些记忆注定让人记忆犹新,这里记录一些第一季中我喜欢的书信。

蔡琴写给杨德昌

这封信是歌手蔡琴写给台湾导演杨德昌的,被誉为“最佳放手信”。 二人十年无性婚姻后因杨德昌有其他爱人而离异。在得知杨德昌逝世后蔡琴发出感慨: “早知道他生命这么短暂,我应该早点放他离开。”

“杨德昌,你怎么可以就这样走了呢?”每个人对爱情的定义和理解不一样,有人选择了哀怨和仇恨,有人选择了宽恕和感激,这也是对待同一件事,完全不同的人生态度。

曹禺与黄永玉

这是来自戏剧作家曹禺和著名画家黄永玉的两封信, 曹禺晚年的作品不尽人意,黄永玉作为一个晚辈写信给他直言“我不喜欢你解放后的戏,一个也不喜欢”“你为势位所误!”,并希望他像萧伯纳,像伏尔泰那样,“到老还那么精确,那么不饶点滴,不饶自己”,“醒来啊马克白,把沉睡赶走!”

曹禺回信中承认自己“泥溷在不情愿的艺术创作中”,并认为他们之间的感情“丰满、美好、深挚、诚厚”。曹禺将这封批评信视为“不可数量的珍宝”,将其裱了起来。

现代社会很少听到批评的声音,尤其作为一个公众人物或艺术大家,在复杂的商业环境下,对待作品的退步也很少有人说出来。黄永玉的开诚布公和曹禺的虚心反思,诠释了何为“君子之交”。

《与韩荆州书》

《与韩荆州书》是李白写给唐朝政治人物韩朝宗的信,韩朝宗因为热心提拔青年才俊而受到大家推崇 ,但李白并没有得到韩朝宗的赏识,反而这封信成为名篇。

“生不用封万户侯,但愿一识韩荆州”“一登龙门,则声价十倍”,李白开篇很直接地拍了韩荆州的马屁,表达希望得到脱颖而出的机会。“白,陇西布衣,流落楚、汉。十五好剑术,遍干诸侯。三十成文章,历抵卿相。虽长不满七尺,而心雄万夫。”讲述身世,让人想起诸葛亮的“臣本布衣,躬耕于南阳,苟全性命于乱世,不求闻达于诸侯”。

“必若接之以高宴,纵之以清谈,请日试万言,倚马可待”,“所以不归他人,而愿委身国士。傥急难有用,敢效微躯”,在说尽溜须拍马之词的同时,能够很明显地感受到李白压抑不住的豪情与潇洒,等不及地施展自己才华的心情。

韩荆州可能并不喜欢这个性格的人才,后来李白遇到贺知章,被推荐给唐玄宗,度过了最辉煌的翰林供奉的三年,所以千里马可能需要合适的伯乐。有人认为此文的谄媚和李白“诗仙”的形象不匹,是李白人生的一个败笔,我倒是觉得原来李白也和每个普通人一样,希望得到赏识和重用。书生意气、豪情万丈,这才是真正的李白。

《报孙会宗书》

这是一封西汉政治家、司马迁外孙杨恽写给好友孙会宗的信。孙劝他闭门思过、戒除骄奢淫逸,杨恽以嬉笑怒骂的口吻写此回信,批驳孙的规劝,并向当时的士大夫们表明“道不同,不相为谋”。

杨恽直言自己“材朽行秽,文质无所底”,“怀禄贪势,不能自退”,“君子游道,乐以忘忧;小人全躯,说以忘罪”,认为犯错后(杨恽之前因为拿皇上开玩笑获罪过)自己一直当个农民就挺好的,“长为农夫以末世矣”,觉得家中喝酒唱歌也是很正常的事。面对好友的规劝,杨恽最后写到“这正是大汉盛世,你去努力吧,跟你没话(方当盛汉之隆,愿勉旃,毋多谈)。”

这封信给我印象很深,乍一读有点无耻,锋芒毕露,仿佛明明白白地告诉你“我不做伪君子,我就是真小人”。但是仔细一想,这里面的人生观颇为有趣。中国古代历来主张忧国忧民的积极自由,却忽视了这种消极自由,就像有人认为人的一生就要做大事、赚大钱、实现梦想,有人则认为平平淡淡、自给自足的过完一生就很好,这是两种不同的人生态度,并无孰对孰错。中国主流文化一直在推崇积极自由,但消极自由也是人的权利和选择。

后有人告发杨恽骄奢的生活,抄家时发现了这封信,在意识形态比较统一的汉代,这种玩世不恭、反主流的消极态度并不会被允许,杨恽因此被腰斩,妻子被流放,孙也被罢官。

闻一多写给父母

1919 年,在清华读书的闻一多积极投身到五四运动中,这封写给父母的信记录了五四运动的细节和感受:

“唯独一帮学生敢冒天下之大不韪,起而抗之。虽于事无大济,然而其心可悲,其志可嘉,其勇可佩”,“一年没回家了,这一年家中又多变故,孩儿我又何尝不想回家看看你们。我留在这里为国家做事,不是说非得有我在国家才可以不亡,而是国家育养了这么多学生,每年花费巨万,一旦有事,学生如果不出力,更待谁人呢?而且孩儿我在学校中总被看做是深明大义的人,刚刚遇到这点儿事,就不能牺牲,难道还能谈什么爱国吗?”

值得一提的是,写这封信时闻一多只有 18 岁,在整个新文化运动时只有陈独秀是 70 后,鲁迅、胡适、傅斯年都是 80 后、90 后,而闻一多是 99 年的:一百年前的中国历史是由 80 后、90 后改变的,正是我们现在的年龄。

100 年前的文字今天读起来仍然铿锵有力,热血澎湃。国运不同,今天的我们可能不会有这样为民族奋起的机会,但不同的年代总有不同实现自我的方式,重要的是这个年纪的我们应该有担当的勇气。

《与高司谏书》

《与高司谏书》作于景祐三年(1036年)。当时主张改革政治的范仲淹因批评弊政,与宰相吕夷简发生冲突。吕夷简给范仲淹加上“越职言事,离间群臣,引用朋党”的罪名。范仲淹由此被贬饶州知州。这时,身为谏官的高若讷,面对范仲淹被贬的错误处置,非但不谏,反而落井下石,跟在吕夷简的后面诋毁范仲淹。欧阳修对此非常不满,于是写下这封信给高若讷。

欧阳修在这封信中真的是骂的非常痛快,让人无可遁形。信中指责高司谏“为言事之官,而俯仰默默,无异众人”,十四年多次怀疑他的人品最终得出结论:“今者推其实迹而较之,然后决知足下非君子也”,“足下在其位而不言,便当去之,无妨他人之堪其任者也”,“是足下不复知人间有羞耻事尔”,“若犹以谓希文不贤而当逐,则予今所言如此,乃是朋邪之人尔。愿足下直携此书于朝,使正予罪而诛之,使天下皆释然知希文之当逐,亦谏臣之一効也。”

在信中欧阳修一一为范仲淹辩护,有理有据,痛骂高司谏位高权贵却毫不作为,酣畅淋漓。北宋时君子的直言纳谏不再是个例,而变成了一种制度,欧阳修字里行间的浩然正气在现代社会读起来,不禁让人唏嘘与感动。

白求恩遗书

加拿大共产党员白求恩不远万里来到中国, 为晋察冀边区的军民救死扶伤。生命弥留之际,他给聂荣臻司令写下这封遗书。

“我在这里十分快乐,我惟一的希望就是能够多做贡献”,白求恩为遗物安排的非常妥当“两张行军床、两双英国皮鞋,你和聂夫人留用吧。马靴、马裤,请转交吕司令。贺将军,也要给他一些纪念品……”,其中并没有什么值钱的物品。“最近两年,是我平生最愉快、最有意义的日子。在这里,我还有很多话要对同志们说,可我不能再写下去了。让我把千百倍的谢忱送给你和千百万亲爱的同志们。”

毛泽东在《纪念白求恩》中高度赞扬了他的国际主义精神:“一个高尚的人,一个纯粹的人,一个有道德的人,一个脱离了低级趣味的人,一个有益于人民的人”,背下来这段话很容易,然而理解可能需要一生的时间。

陈觉与赵云霄[1][2]

这是两位革命烈士的信,看得人心如刀割。一封是丈夫就义前写给妻子的诀别信,一封是母亲留给尚在襁褓中女儿的遗书,二人先后英勇就义,牺牲时年仅 25 岁、23 岁。

“谁无父母,谁无儿女,谁无情人!我们正是为了救助全中国人民的父母和妻儿,所以牺牲了自己的一切。我们虽然是死了,但我们的遗志自有未死的同志来完成。大丈夫不成功便成仁,死又何憾!”

《贺进士王参元失火书》

这是一封非常有意思的信,唐元和年间,王参元家遭遇大火,柳宗元“始而骇”、“中而疑”、“终乃大喜”,写此信向王参元祝贺。

柳宗元直指一般人可能会说“皆曰盈虚倚伏,去来之不可常”,或者是“将大有为也,乃始厄困震悸,于是有水火之孽,有群小之愠,劳苦变动,而后能光明”,过去有很多人相信这一套,实际很不靠谱。作者接下来点明了祝贺的原因:“京城人多言足下家有积货,士之好廉名者,皆畏忌,不敢道足下之善”,意思是你家里太有钱了,有名之士忌讳于此,不敢说你好话,容易被流言蜚语弄得百口难辩。幸运的是,这一把火之后,所有人的担心、顾虑都烟消云散,虽然钱财一无所有,但你的才能可以好好传承,不会被玷污。

这篇文章揭露了几个传统:一是类似于“天将降大任于斯人也”,“先灾后福”的虚礼;二是位高权贵的人不能太有钱的“清流”传统;三是“仇富”传统。

]]>
EOS 开发:合约 https://livc.io/blog/226 2018-06-12T00:00:00+00:00 Zhao Li https://livc.io/blog/226 EOS 现在更新非常频繁,之前的命令可能很快就会有变动,于是我新编译了一个版本,不再使用之前的 Docker 环境。

EOS 的合约在 ~/eos/contracts 目录之下,比如 hello 合约为 ~/eos/contracts/hello/hello.cpp

#include <eosiolib/eosio.hpp>
using namespace eosio;

class hello : public eosio::contract {
  public:
      using contract::contract;

      /// @abi action
      void hi( account_name user ) {
         print( "Hello, ", name{user} );
      }
};

EOSIO_ABI( hello, (hi) )

从 CPP 编译成 WebAssembly 文件:

eosiocpp -o hello.wast hello.cpp

生成 abi 文件:

$ eosiocpp -g hello.abi hello.cpp
Generated hello.abi ...

上传合约到账户中(其中 livc 是 account name):

$ cleos --url http://127.0.0.1:8887 set contract livc ~/eos/contracts/hello -p livc
Reading WAST/WASM from /Users/zhao/eos/contracts/hello/hello.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: e35b8ec816d7556fee73f12c31c64e146c8a7af0fa56846a2466b87ef506c7ef  4168 bytes  5181 us
#         eosio <= eosio::setcode               {"account":"livc","vmtype":0,"vmversion":0,"code":"0061736d01000000013b0c60027f7e006000017e60027e7e0...
#         eosio <= eosio::setabi                {"account":"livc","abi":"0e656f73696f3a3a6162692f312e30000102686900010475736572046e616d6501000000000...

$ cleos --url http://127.0.0.1:8887 push action livc hi '["hhhhh"]' --permission livc@active
executed transaction: a193f474503bb79ea6ecafa04419ea851cf4fd5d88c18710f0d8052a2f65e2bb  104 bytes  1269 us
#          livc <= livc::hi                     {"user":"hhhhh"}

其中,-p 代表使用该账户的 active 的授权,cleos 调用了 setcodesetabi 两个函数。

Token 合约

eosio.token 合约是一个 token 标准合约,类似于 ETH 的 ERC20 标准。

eosiocpp -o eosio.bios.wast eosio.bios.cpp

由于目录已存在 abi 文件,不需再次生成。

$ cleos --url http://127.0.0.1:8887 set contract eosio ~/eos/contracts/eosio.bios -p eosio
Reading WAST/WASM from /Users/zhao/eos/contracts/eosio.bios/eosio.bios.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: 0fa7093a92ed900c88aaad2cf8b9a0e142d19625731cbd35eb4b5fc87b05cd43  3712 bytes  847 us
#         eosio <= eosio::setcode               {"account":"eosio","vmtype":0,"vmversion":0,"code":"0061736d0100000001621260037f7e7f0060057f7e7e7e7e...
#         eosio <= eosio::setabi                {"account":"eosio","abi":"0e656f73696f3a3a6162692f312e30050c6163636f756e745f6e616d65046e616d650f7065...

创建 eosio.token 账户和合约:

$ cleos create key
(eosio.token owner)
Private key: 5HuTB56H49GP6VnKYk5xHNXQBESfqs8nwBCuhekbbLgS9PPA7mh
Public key: EOS71oCDtXFzjU1p5rn4oBo2VVGh37fSYrXmcusBv53FQyLMwrzEq

$ cleos create key
(eosio.token private)
Private key: 5J9svtsttiFvfHdeHwNruyfRfAF8i9yC1EcSzWUYy6MniuT1SAt
Public key: EOS4xo6bcVrApUY3BGALR29UmvykqdwACeDnzTAgeFNuHiJEMHUFj

$ cleos wallet create -n eosio.token
Creating wallet: eosio.token
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5JiCuwwW3qJxU4mj8qvQYsHKGE78FmUtFH8UhJorW2hkmEWrevA"

$ cleos wallet import 5HuTB56H49GP6VnKYk5xHNXQBESfqs8nwBCuhekbbLgS9PPA7mh
imported private key for: EOS71oCDtXFzjU1p5rn4oBo2VVGh37fSYrXmcusBv53FQyLMwrzEq

$ cleos wallet import 5J9svtsttiFvfHdeHwNruyfRfAF8i9yC1EcSzWUYy6MniuT1SAt
imported private key for: EOS4xo6bcVrApUY3BGALR29UmvykqdwACeDnzTAgeFNuHiJEMHUFj

$ cleos --url http://127.0.0.1:8887 create account eosio eosio.token EOS71oCDtXFzjU1p5rn4oBo2VVGh37fSYrXmcusBv53FQyLMwrzEq EOS4xo6bcVrApUY3BGALR29UmvykqdwACeDnzTAgeFNuHiJEMHUFj
executed transaction: b4ea4231f9cdcc5c97d9777bdf4a0d67a49a3312674fe62571e8de76a43aa803  200 bytes  621 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"eosio.token","owner":{"threshold":1,"keys":[{"key":"EOS71oCDtXFzjU1p5rn4o...

$ cleos --url http://127.0.0.1:8887 set contract eosio.token ~/eos/contracts/eosio.token -p eosio.token
Reading WAST/WASM from /Users/zhao/eos/contracts/eosio.token/eosio.token.wasm...
Using already assembled WASM...
Publishing contract...
executed transaction: effb485662fe1003b00a872aca556e5f16f6715c872ce61657302a09d3d87b0a  8112 bytes  1124 us
#         eosio <= eosio::setcode               {"account":"eosio.token","vmtype":0,"vmversion":0,"code":"0061736d01000000017e1560037f7e7f0060057f7e...
#         eosio <= eosio::setabi                {"account":"eosio.token","abi":"0e656f73696f3a3a6162692f312e30010c6163636f756e745f6e616d65046e616d65...

$ cleos --url http://127.0.0.1:8887 push action eosio.token create '["eosio","1000000000.0000 EOS",0,0,0]' -p eosio.token
executed transaction: f5e3a7f3138f03c8dcac789e40bc8af2ac76750581aa9f97ab241edbdee8b4c8  120 bytes  1460 us
#   eosio.token <= eosio.token::create          {"issuer":"eosio","maximum_supply":"1000000000.0000 EOS"}

创建一个账户 bob 并给他转账:

$ cleos create key
(bob owner)
Private key: 5JPZkcPwVfRAZYjD2CkLLf1TwsaWk7JGJcUZJM9Vtw4XQuVXsh1
Public key: EOS7URUGippnvXCifEao2quScqHGanjzLqxGdPyrgVTuMCe5PGQxb

$ cleos create key
(bob private)
Private key: 5Jg1Y9u8HDsMzo7WtSXHXkRwAbdy9hBsgTMf1gSoZDRbp76G4Ge
Public key: EOS6MyaP2sPpgbXARnHkSkVPU5rid7YTTP44Xsr7vnKVZCxwxJSY1

$ cleos wallet create -n bobwallet
Creating wallet: bobwallet
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5J1SNSox7ozdETfnDeFFQYYrGjCwsV7trcoyX4GbCtcjtfpwqny"

$ cleos wallet import 5JPZkcPwVfRAZYjD2CkLLf1TwsaWk7JGJcUZJM9Vtw4XQuVXsh1
imported private key for: EOS7URUGippnvXCifEao2quScqHGanjzLqxGdPyrgVTuMCe5PGQxb

$ cleos wallet import 5Jg1Y9u8HDsMzo7WtSXHXkRwAbdy9hBsgTMf1gSoZDRbp76G4Ge
imported private key for: EOS6MyaP2sPpgbXARnHkSkVPU5rid7YTTP44Xsr7vnKVZCxwxJSY1

$ cleos --url http://127.0.0.1:8887 create account eosio bob EOS7URUGippnvXCifEao2quScqHGanjzLqxGdPyrgVTuMCe5PGQxb EOS6MyaP2sPpgbXARnHkSkVPU5rid7YTTP44Xsr7vnKVZCxwxJSY1
executed transaction: 32269bbfa553468ee798e5c2f70df1262258eecfa241eabe800d2bae2651775e  200 bytes  232 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"bob","owner":{"threshold":1,"keys":[{"key":"EOS7URUGippnvXCifEao2quScqHGa...

$ cleos --url http://127.0.0.1:8887 push action eosio.token issue '[ "bob", "100.0000 EOS", "memo" ]' -p eosio
executed transaction: 39d7ba273c549db9ba1746a74938b026b57b8a3f0bf49919529b25119498767d  128 bytes  1622 us
#   eosio.token <= eosio.token::issue           {"to":"bob","quantity":"100.0000 EOS","memo":"memo"}
#   eosio.token <= eosio.token::transfer        {"from":"eosio","to":"bob","quantity":"100.0000 EOS","memo":"memo"}
#         eosio <= eosio.token::transfer        {"from":"eosio","to":"bob","quantity":"100.0000 EOS","memo":"memo"}
#           bob <= eosio.token::transfer        {"from":"eosio","to":"bob","quantity":"100.0000 EOS","memo":"memo"}

再创建一个账号 Mary,从 Bob 给 Mary 转账:

$ cleos create key
Private key: 5K4ooajerHnUikiQG1pfrAxsveoBg7Zs7BMkrgeyBZLTszmL4R2
Public key: EOS8jxG15Zd4MGGrb5aNo3ZoBGEx9v7uCvaXxeWqni7HraMGtshiw

$ cleos create key
Private key: 5JS9VHiHgpjC5P1bFjjGDumANoR3nhibFwJpDrmqg25Jk4EQU75
Public key: EOS537AH7wwzYRHc4sUjnXDsJ4pu8rSxCJLrNp2XdtcHrCE34DZ8X

$ cleos wallet create -n marywallet
Creating wallet: marywallet
Save password to use in the future to unlock this wallet.
Without password imported keys will not be retrievable.
"PW5J2gAWRz7hqcT8ASU66XeRsEDHnfrAqj8djYyXs8vNBWf6Th2Fr"

$ cleos wallet import 5K4ooajerHnUikiQG1pfrAxsveoBg7Zs7BMkrgeyBZLTszmL4R2
imported private key for: EOS8jxG15Zd4MGGrb5aNo3ZoBGEx9v7uCvaXxeWqni7HraMGtshiw

$ cleos wallet import 5JS9VHiHgpjC5P1bFjjGDumANoR3nhibFwJpDrmqg25Jk4EQU75
imported private key for: EOS537AH7wwzYRHc4sUjnXDsJ4pu8rSxCJLrNp2XdtcHrCE34DZ8X

$ cleos --url http://127.0.0.1:8887 create account eosio mary EOS8jxG15Zd4MGGrb5aNo3ZoBGEx9v7uCvaXxeWqni7HraMGtshiw EOS537AH7wwzYRHc4sUjnXDsJ4pu8rSxCJLrNp2XdtcHrCE34DZ8X
executed transaction: 1d0aac267f86a645f278910a20c527b73fda20832e315f26b82d6b388986a144  200 bytes  469 us
#         eosio <= eosio::newaccount            {"creator":"eosio","name":"mary","owner":{"threshold":1,"keys":[{"key":"EOS8jxG15Zd4MGGrb5aNo3ZoBGEx...

$ cleos --url http://127.0.0.1:8887 push action eosio.token transfer '[ "bob", "mary", "25.0000 EOS", "m" ]' -p bob
executed transaction: cb664fc62c5bbf480aa73ab8ae19aecd85c68b09d9fdd70f0e7ee0e83a7ee433  128 bytes  976 us
#   eosio.token <= eosio.token::transfer        {"from":"bob","to":"mary","quantity":"25.0000 EOS","memo":"m"}
#           bob <= eosio.token::transfer        {"from":"bob","to":"mary","quantity":"25.0000 EOS","memo":"m"}
#          mary <= eosio.token::transfer        {"from":"bob","to":"mary","quantity":"25.0000 EOS","memo":"m"}

检查余额:

$ cleos --url http://127.0.0.1:8887 get currency balance eosio.token mary
25.0000 EOS

$ cleos --url http://127.0.0.1:8887 get currency balance eosio.token bob
75.0000 EOS

Reference

  • https://www.eosdocs.io/dappdevelopment/tokencontract/
  • https://www.eosdocs.io/dappdevelopment/helloworldcontract/
]]>
Mysql 数据变动备份 https://livc.io/blog/225 2018-06-06T00:00:00+00:00 Zhao Li https://livc.io/blog/225 本文保存 Mysql 数据库变动的思路是把变动(前或后)的数据保存到一个新的表中。

假如原表名为 tablename,创建一个新表命名为 history_table,其中字段都跟 tablename 一致,创建一个触发器命名为 trigger1,在每次更新后都把新的数据插入到备份表中,这样就知道每次数据库做了哪些改动:

CREATE TRIGGER `trigger1`
AFTER UPDATE ON `tablename`
FOR EACH ROW
    INSERT INTO history_table                 
    VALUES
    (
        NEW.field1,
        NEW.field2
    );

把里面的 field1, field2 换成自己表中的字段即可。

也可以在 phpmyadmin 中直接创建 trigger,

直接在定义中写入

INSERT INTO history_table                 
VALUES
(
    NEW.field1,
    NEW.field2
);

即可。

可能会有的问题是,如果原表主键是数字,那么修改原表这一行一次以上的话,备份表就会出现两行相同的主键数据。我们可以在备份表中另建一个主键来解决。

Reference

  1. https://kahimyang.com/kauswagan/code-blogs/552/create-history-record-for-every-change-in-mysql-table-audit-trail-mysql-trigger
]]>
LNMP + Laravel https://livc.io/blog/224 2018-06-05T00:00:00+00:00 Zhao Li https://livc.io/blog/224 本文是在 LNMP 1.5 环境下部署 Laravel 的教程,其中 LNMP 使用 https://lnmp.org 的一键安装包。

打开 proc_open

laravel 需要 proc_open 等函数,需要在 /usr/local/php/etc/php.ini 中的 disable_functions 删掉 proc_openproc_get_status,保存后 lnmp php-fpm restart 重启 php。

NGINX 配置

在 nginx 的配置中,设置了强制跳转 https,也包含了伪静态的重写文件。

server
    {
        listen 80;
        #listen [::]:80;
        server_name freecandy.one www.freecandy.one;
        rewrite ^(.*)$ https://freecandy.one$1 permanent;

    }

server
    {
        listen 443 ssl http2;
        #listen [::]:443 ssl http2;
        server_name freecandy.one ;
        index index.php index.htm index.html default.html default.htm default.php;
        root  /home/wwwroot/freecandy.one/public;
        ssl on;
        ssl_certificate /usr/local/nginx/conf/ssl/freecandy.one/fullchain.cer;
        ssl_certificate_key /usr/local/nginx/conf/ssl/freecandy.one/freecandy.one.key;
        ssl_session_timeout 5m;
        ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
        ssl_prefer_server_ciphers on;
        ssl_ciphers "EECDH+CHACHA20:EECDH+CHACHA20-draft:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5";
        ssl_session_cache builtin:1000 shared:SSL:10m;
        ssl_dhparam /usr/local/nginx/conf/ssl/dhparam.pem;

        include rewrite/laravel.conf;

        location ~ \.php$ {
            fastcgi_split_path_info ^(.+\.php)(/.+)$;
            fastcgi_pass  unix:/tmp/php-cgi.sock;
            fastcgi_index index.php;
            include fastcgi_params;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
        }        

        location ~ .*\.(gif|jpg|jpeg|png|bmp|swf)$
        {
            expires      30d;
        }

        location ~ .*\.(js|css)?$
        {
            expires      12h;
        }

        location ~ /.well-known {
            allow all;
        }

        location ~ /\.
        {
            deny all;
        }

        access_log off;

    }

修改权限

通过 chown -R www:www freecandy.one 将网站目录的权限从 root 修改为 www。默认的路径在 /home/wwwroot/freecandy.one/

删掉防跨目录

在Thinkphp、codeigniter、Laravel等框架下,网站目录一般是在public下,但是public下的程序要跨目录调用public上级目录下的文件,因为LNMP默认是不允许跨目录访问的,所以都是必须要将防跨目录访问的设置去掉,有时候这些框架类的程序提示500错误也可能是这个问题引起的。

LNMP 1.4上如果不想用防跨目录或者修改.user.ini的防跨目录的目录还需要将 /usr/local/nginx/conf/fastcgi.conf 里面的fastcgi_param PHP_ADMIN_VALUE “open_basedir=$document_root/:/tmp/:/proc/”; 在该行行前添加 # 或删除改行,需要重启nginx。

LNMP 1.4上也可以直接使用lnmp1.4/tools/ 目录下的 ./remove_open_basedir_restriction.sh 进行移除。

其他

删掉网站目录时,需要先 chattr +i /网站目录/.user.ini 之后即可删除。

Reference

  1. https://lnmp.org/faq/lnmp-vhost-add-howto.html
]]>