This repository has been archived by the owner on Aug 22, 2018. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathatom.xml
136 lines (75 loc) · 84.1 KB
/
atom.xml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
<title>Xiaoxing Ye's Farmland</title>
<subtitle>Blog for everything</subtitle>
<link href="/atom.xml" rel="self"/>
<link href="https://xiaoxing.us/"/>
<updated>2018-01-30T16:05:53.390Z</updated>
<id>https://xiaoxing.us/</id>
<author>
<name>Xiaoxing Ye</name>
</author>
<generator uri="http://hexo.io/">Hexo</generator>
<entry>
<title>Utilizing BlockCert - Blockchain-Based Educational Certificates</title>
<link href="https://xiaoxing.us/2018/01/31/Utilizing-BlockCert-Blockchain-Based-Educational-Certificates/"/>
<id>https://xiaoxing.us/2018/01/31/Utilizing-BlockCert-Blockchain-Based-Educational-Certificates/</id>
<published>2018-01-30T16:02:24.000Z</published>
<updated>2018-01-30T16:05:53.390Z</updated>
<content type="html"><![CDATA[<p>Imagine that, one day you graduate from CUHK-Shenzhen and you don't receive a paper diploma. While you are complaining it to your friend, saying that "the University is too stingy to give a single paper", you receive an email, with title "Your Digital Diploma". With curiosity, you open the email and it says, "Welcome to digital world. Attached is your e-diploma, and you can print it yourself". Uh-huh, e-diploma? Sounds to be cool.</p><p>Recently, blockchain has become a hit topic, especially on cryptocurrencies. Someone says that it redefines "Trust" since using blockchain you no longer need to trust <strong>anyone</strong> but algorithm. What if it can be used to issue diplomas? But there is a sad story — the Massachusetts Institute of Technology, yes the MIT, has already announced that it will issue diplomas to around one hundred graduates utilizing the bitcoin. Failed to be the first in the world, what about let CUHK-Shenzhen be the first in Asia? It sounds to be a good idea.</p><p>Before we can issue CUHK-Shenzhen diplomas, let's try to walk through the process. Luckily, MIT Media Lab open-sourced the whole toolkits so we can try.</p><h1>Before we go on...</h1><p>Before talking about BlockCert, we need to know some basic knowledges...</p><ul><li>Markle Tree</li><li>Blockchain</li><li>Digital Certificates (what and why)</li></ul><h2>What is Markle Tree?</h2><p>(To be written)</p><p><a href="http://www.cnblogs.com/fengzhiwu/p/5524324.html" target="_blank" rel="noopener">http://www.cnblogs.com/fengzhiwu/p/5524324.html</a></p><h2>What is Blockchain?</h2><p>TL;DR: Blockchain stores all information and once info is kept it is signed and permantly stored. No one can modify or delete any information.</p><p>Blockchain is like a huge, global, and decentralized spreadsheet, keeping a track of who sent how many coins to whom, and what the balance of every account is. All people (miners) in the network stores and maintain the blockchain. When you check the information like transaction or personal balance, it reads data on the blockchain, not in any personal systems.</p><h2>What is digital certificates?</h2><p>The digital certificate is a digital document that validates the participation of a user in any activities defined. The digital certificate is characterized by storing all the relevant information of the certificate so that it can be verified by means of encryption methods.</p><h2>Why digital certificates?</h2><p><strong>It is transparent:</strong> The digital certificate has the ability to be verified without the need to contact directly the institution that issues it, because it can verify the transaction and the identities of the participants (issuer and recipient of the certificate) since this information is public.</p><p><strong>It is safe:</strong> On the other hand, while the transaction is public, the content of the certificate and the personal information of the sender and receiver is private.</p><h1>Let's Get Started!</h1><p><img src="https://static.notion-static.com/62c70d8c-e27f-4bf6-beb1-084452ab54ec/0_LcgQy9J55lxVbGIU.png" alt=""></p><p>Overview of our digital certification architecture (Source: <a href="https://medium.com/mit-media-lab/what-we-learned-from-designing-an-academic-certificates-system-on-the-blockchain-34ba5874f196" target="_blank" rel="noopener">https://medium.com/mit-media-lab/what-we-learned-from-designing-an-academic-certificates-system-on-the-blockchain-34ba5874f196</a>)</p><p>The toolkits consist of three parts:</p><ul><li><a href="https://github.com/digital-certificates/cert-schema" target="_blank" rel="noopener">cert-schema</a>: The data standard for digital certificates. The schema is actually an extension of <a href="https://www.imsglobal.org/sites/default/files/Badges/OBv2p0/index.html" target="_blank" rel="noopener">Open Badges</a>. A digital certificate is essentially a JSON file.</li><li><a href="https://github.com/digital-certificates/cert-issuer" target="_blank" rel="noopener">cert-issuer</a>: It takes a JSON certificate, creates a hash to identify the certificate, and issues the certificate by broadcasting a transation (Bitcoin or Ethereum) from the issuing institution's address to a recipient's address, with the bash embedded within the transaction data field.</li><li><a href="https://github.com/digital-certificates/cert-viewer" target="_blank" rel="noopener">cert-viewer</a>: A flask demo to display and verify digital certificates after been issued. It also provides the ability for users to request certificates and to generate a new Bitcoin identity.</li></ul><p>In this tutorial, we will talk about the second part — cert-issuer. We will not work on a real institution, since we are only to get a sense of it. And, we will use Ropsten Ethereum testnet, for the reason that we are poor to get real cryptocurrencies (just a joke).</p><h2>Get the source code and Install required packages</h2><p>You are highly recommended to use virtualenv.</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> https://github.com/blockchain-certificates/cert-issuer.git && <span class="built_in">cd</span> cert-issuer</span><br></pre></td></tr></table></figure></p><p><img src="https://static.notion-static.com/5752641d-8103-4b84-9fbb-a346537e18e6/Untitled" alt=""></p><p>You are expected to... fail. That's because there are two conflicting libraries in the project. Merkletools requires “exactly” pysha3 1.01b, while cert-tools require pysha3 1.0.2 or greater. To solve the problem, go to the site-packages folder:</p><p><img src="https://static.notion-static.com/b67489b9-2374-4e7c-bd4a-d2538c8be581/Untitled" alt=""></p><p>The folder after "Installed" is what we need. Then enter "merkletools-1.0.2-py3.6.egg" folder, edit the METADATA and replace "pysha3 (==1.0b1)" to <code>pysha3 (>=1.0b1)</code> then save. You need to do the same thing on metadata.json file.</p><p>If you don't see these files, edit the one in <code>/merkletools-1.0.2-py3.6.egg/EGG-INFO/requires.txt</code> .</p><p>Go back to the cert-issuer folder and re-run</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python setup.py install</span><br></pre></td></tr></table></figure></p><p>Everything should be fine now.</p><h2>Create an Ethereum issuing address</h2><p>In Ethereum a public/private key pair is the same accross all test/main networks. So, we don't need to have anew key pair if later we want it to run on main network (the one we will use real USD).</p><p>To create a new wallet, we can use a local wallet</p><p>First, go to <a href="https://www.myetherwallet.com/" target="_blank" rel="noopener">https://www.myetherwallet.com/</a>. If you plan to go further to production part, turn off your Internet connection when you are already on the create wallet page.</p><p><img src="https://static.notion-static.com/b30e1b9b-2eed-48a8-b355-f99d9011b15a/Untitled" alt=""></p><p>Do you see the big input box? Yes, enter your desired password for your wallet. Write it down somewhere and save it, otherwise you will lose your funds.</p><p><img src="https://static.notion-static.com/1e6bc4ad-0f45-4df5-8218-8e919388049e/Untitled" alt=""></p><p>Then, you will be required to download a Keystore file. Read the instruction carefully, and, save it. After clicking Continue, you will see your private key.</p><p><img src="https://static.notion-static.com/2e36671c-8d23-4a04-af29-0a8938153786/Untitled" alt=""></p><p>Of course, I won't let you see it. Copy the private key. You should print a paper wallet (or save as PDF). The paper wallet looks like...</p><p><img src="https://static.notion-static.com/64164e20-4c04-4e4f-a1a3-e06b772d67ed/Untitled" alt=""></p><p>Yes, like a air ticket. Click the "Save Your Address" to continue. In next page, we will need to read the public key (known as Account # or Address). It is what you will use and share with people later. Find the colorful address icon. Make sure it matches your paper wallet & whenever you enter your address somewhere.</p><p><img src="https://static.notion-static.com/f3b7cf20-4602-4996-9f44-10701dfb8668/Untitled" alt=""></p><p>You may use the Keystore file or your Private Key to continue. Enter the wallet password. What? You forget it? Regenerate your wallet and remember the password.</p><p><img src="https://static.notion-static.com/60c0929a-8fff-4d30-a5d8-e0ecb426cbfd/Untitled" alt=""></p><p>Here you will get your public address. Copy it and save for later use. (DON'T send ETH to this account. I already delete the private key.)</p><h2>Get some coins</h2><p>Before we can issue certificates, we need to have sufficient funds to cover the transaction fee. Why transaction fee? It is paid to miners for their work. The current fee is 0.00008 ETH (Well, only 0.082 dollars. Not a big deal). But remember? We are poor and we are on testnet, so why paying money? We can get some free coins from the network. You can request test coins by searching for "Testnet Faucet", and entering your issuing public address.</p><p>To ease your burden, I have gotten one for you: <a href="http://faucet.ropsten.be:3001/" target="_blank" rel="noopener">http://faucet.ropsten.be:3001/</a>. Enter your public key and click "Send me 3 test ether!".</p><p><img src="https://static.notion-static.com/7ba975a4-2448-4a50-85eb-519778d420f8/Untitled" alt=""></p><p>Then, after a few minutes, check the network to see if you get the money here: https://ropsten.etherscan.io/address/<Your Public Key>.</p><p><img src="https://static.notion-static.com/63caf01a-45cb-45fa-88d3-d8d4cd082b0a/Untitled" alt=""></p><p>See the ETH Balance, it is 3 ETH. Cool, we are rich now (daydreaming).</p><h2>Configuring cert-issuer</h2><p>It is time to configure the instance. But wait, you need to save you private key to somewhere. It is recommended to store the private key on a USB stick and unplug it when not used. But to save time plugging in and out, we will save the private key locally. For example, <code>/Users/xiaoxing/Projects/blockchain-certificates/ethereum</code> folder and <code>pk</code> file.</p><p>Then, you should see a <code>conf_ethtest.ini</code> under the <code>cert-issuer</code> root folder. Open it using any of your favourite editor. Fill in the issuing_address, choose ethereum_ropsten as the blockchain, enter the usb_name and key_file as the private key storage location, and set the three dirs. An example is given here: <a href="https://gist.github.com/Yexiaoxing/74a55d49fbfd5275b698a9ad6f71c9d3" target="_blank" rel="noopener">https://gist.github.com/Yexiaoxing/74a55d49fbfd5275b698a9ad6f71c9d3</a>. Remember to rename the config to conf.ini.</p><h2>Issuing</h2><p>Run <code>cert-issuer -c conf.ini</code> to see if everything is working.</p><p>You will see "No certificates to process" in the output. It is correct since we have not put any certificates. Let's do it.</p><p>To save some time, we can use the sample certs:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cp ./examples/data-testnet/unsigned_certificates/* ./data/unsigned_certificates</span><br></pre></td></tr></table></figure></p><p>Here you need to edit the unsigned certificates, replace "msBCHdwaQ7N2ypBYupkp6uNxtr9Pg76imj" with your public key.</p><p>Then, you need to find a place to host your issuer profile. What is issuer profile? From <a href="https://www.imsglobal.org/sites/default/files/Badges/OBv2p0/index.html#Profile" target="_blank" rel="noopener">Open Badges</a>, a Profile is a collection of information that describes the entity or organization using Open Badges. The main usage is to verify the cert is issued from proved person. Since we are using our owned public key, we need to host the profile file by ourselves.</p><p>Blockcerts itself provides two samples, one is issuer profile and another one is revocation list. First we need to download the two files.</p><ul><li><a href="https://www.blockcerts.org/samples/2.0/issuer-testnet.json" target="_blank" rel="noopener">https://www.blockcerts.org/samples/2.0/issuer-testnet.json</a></li><li><a href="https://www.blockcerts.org/samples/2.0/revocation-list-testnet.json" target="_blank" rel="noopener">https://www.blockcerts.org/samples/2.0/revocation-list-testnet.json</a></li></ul><p>Then, open the two files, and you will see a compressed json. What you need to do is first replace "msBCHdwaQ7N2ypBYupkp6uNxtr9Pg76imj" with your public key in issuer-testnet.json file, and upload it to somewhere, like GitHub, where you need to get a stable link for direct download. Then, replace the links in the two json files with the correct one.</p><p>It is hard to explain in language... You may check my examples here: <a href="https://github.com/Yexiaoxing/blockcerts-trial" target="_blank" rel="noopener">https://github.com/Yexiaoxing/blockcerts-trial</a> . You will also need to change the links in the sample cert.</p><p><s>Then, re-run again. You are... yes, expected to fail again. This time you need to modify <code>site-packages/cert_issuer-2.0.11-py3.6.egg/cert_issuer/ethereum/connectors.py</code> and add one more argument to the last <code>get_providers_for_chain</code> function, like:</s></p><p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="function"><span class="keyword">def</span> <span class="title">get_providers_for_chain</span><span class="params">(chain, local_node=False)</span>:</span></span><br></pre></td></tr></table></figure></p><p>Update: You are no longer needed to do this modification since the repo has accepted my PR.</p><p>Then, run again and you should get the result:</p><p><img src="https://static.notion-static.com/8d0d0bb8-0aae-4c7b-b087-b80510136141/Untitled" alt=""></p><p>Read the debug infos, it is useful. You will find a string of txid, which is your transaction ID (highlighted in the screenshot). Now you can check this transaction using Etherscan (https://ropsten.etherscan.io). An example is given here: <a href="https://ropsten.etherscan.io/tx/0x58c8baddc01711c4c35f2ca177ff93994c9c521e5c46e440f907ef145ceddd5b" target="_blank" rel="noopener">https://ropsten.etherscan.io/tx/0x58c8baddc01711c4c35f2ca177ff93994c9c521e5c46e440f907ef145ceddd5b</a>.</p><p>Now you get a blockchain-baked certificate under data/blockchain_certificates. But how to verify it?</p><h2>Verify the certificate</h2><p>First, you need to clone the cert_verifier repo by:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> [https://github.com/blockchain-certificates/cert-verifier.git](https://github.com/blockchain-certificates/cert-verifier.git) && <span class="built_in">cd</span> cert-verifier</span><br></pre></td></tr></table></figure></p><p>Then, remember that you have a new certificate? Copy to the verifier folder, and run the verifier by</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">python cert_verifier/verifier.py <filename></span><br></pre></td></tr></table></figure></p><p>If your certificate is true, you will see some "passed" without "failed".</p><p><img src="https://static.notion-static.com/e6dd98ca-77e1-4565-bcc6-e0226b11ed01/Untitled" alt=""></p><h2>Host a Certificate Viewer</h2><p>What if you want to show your certificate to others? It is not a good idea to share... json file, right? The MIT project has provided a Flask app to display and verify blockchain certificates.</p><p>First, you need to clone the app:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">git <span class="built_in">clone</span> [https://github.com/blockchain-certificates/cert-viewer.git](https://github.com/blockchain-certificates/cert-viewer.git) && <span class="built_in">cd</span> cert-viewer</span><br></pre></td></tr></table></figure></p><p>Then, before you can use the app, you need to modify some config. Make a copy of conf_template.ini and name it as conf.ini. Follow the instructions here: <a href="https://github.com/blockchain-certificates/cert-viewer/#configuration" target="_blank" rel="noopener">https://github.com/blockchain-certificates/cert-viewer/#configuration</a>.</p><p>After you finished the configure, install the required packages by</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">pip install .</span><br></pre></td></tr></table></figure></p><p>Remember to copy the signed cert to cert_data/. Then run the app <code>python [run.py](http://run.py/) -c conf.ini</code>. And, visit the site using your favorite website, click on one of the recent cert and verify.</p><p>Well, unfortunately, cert-viewer isn't support ethernet yet. So you will not be able to view your newly signed cert. But, you can get a sense by viewing the sample certs.</p><h1>Other Resources</h1><p>If you want to put this into production (though, I don't recommend), you can download some tools here: <a href="https://github.com/blockchain-certificates/cert-tools" target="_blank" rel="noopener">https://github.com/blockchain-certificates/cert-tools</a>. You can create your owned certificate template and instantiate certificate batch.</p><p>If you want to learn more about it, you can read the cert schema, which is based on Open Badges: <a href="https://github.com/blockchain-certificates/cert-schema" target="_blank" rel="noopener">https://github.com/blockchain-certificates/cert-schema</a></p>]]></content>
<summary type="html">
<p>Imagine that, one day you graduate from CUHK-Shenzhen and you don't receive a paper diploma. While you are complaining it to your friend,
</summary>
<category term="Tutorials" scheme="https://xiaoxing.us/categories/Tutorials/"/>
<category term="Tutorials" scheme="https://xiaoxing.us/tags/Tutorials/"/>
<category term="blockcerts" scheme="https://xiaoxing.us/tags/blockcerts/"/>
<category term="blockchain" scheme="https://xiaoxing.us/tags/blockchain/"/>
</entry>
<entry>
<title>Happy New Year!</title>
<link href="https://xiaoxing.us/2018/01/02/Happy-New-Year/"/>
<id>https://xiaoxing.us/2018/01/02/Happy-New-Year/</id>
<published>2018-01-01T19:20:01.000Z</published>
<updated>2018-01-01T18:27:30.572Z</updated>
<content type="html"><![CDATA[<p>Happy New Year, my dearest readers. The following contents are in Chinese (yes I'm too lazy to translate...)</p><p>Hello, 2018.</p><p>2017 是从修电脑开始的,而 2018,是从看电影开始的。</p><p>过去的 2017 年里,发生了很多很多。经历了两场令人崩溃的期末考试,渡过了让人抑郁的秋季学期。还好,都活过来了。暑假去了沙田上 Summer School,宿舍不错。</p><p>现在想了想,好像自己什么也没做。成绩没多好,项目一般般,研究?等于零。顺便还挂了场面试。但是好在身边还有几个朋友,能深夜谈谈心。</p><p>回想起去年的今天,曾经立下目标要做什么什么,好像也没完成几件。书真的没读几本,虽然书架上一堆书。代码也没写多少行,一年加起来有 1w 行没?可能还没有。倒是胖了不少,算是唯一的成就吧。</p><p>Well,2017 已经过去了,接下来该迎接 2018 了。接下来的这一年是很关键的一年了,要做研究、考托福、准备 GRE/GMAT(其实这两是啥我还没分清)、申研究生,事情那么那么多,一个人撑着还是挺累的。还好,我这个人还比较能熬。</p><p>这一年还要做什么呢,可能第一件事是开始写博客吧。说来好玩,Boss 让写的技术文章被外国人看到了还发邮件来表示感谢。虽然也不知道写什么,随便写写好了。</p><p>编程真的要好好开始学了。半桶水的 Python、忘的差不多的 C++(也是因为它面试才被 fail…),再学门别的什么,Go 或者 Node.js?</p><p>开源社区这边,之前翻译了个 gnome-tweak 被表扬翻译质量高,然后就弃坑了。今年开始给社区多做点贡献好了。</p><p>成绩什么的,随缘了… 倒是希望能多参与学院在学术方面的工作,毕竟真的… 影响别人还影响自己,课都没得上。</p><p>人际关系嘛,找个女朋友,找不到就算了:)有时间(而且有钱)的话去旅个游,去年暑假打算去上海来着都没去成。(如果学校有什么公费旅游的项目记得带上我(划去))</p><p>写了这么多,感谢能看到这的你。</p><p>新年快乐。</p>]]></content>
<summary type="html">
<p>Happy New Year, my dearest readers. The following contents are in Chinese (yes I'm too lazy to translate...)</p>
<p>Hello, 2018.</p>
<p>2
</summary>
<category term="Diary" scheme="https://xiaoxing.us/categories/Diary/"/>
<category term="Diary" scheme="https://xiaoxing.us/tags/Diary/"/>
<category term="Random Thoughts" scheme="https://xiaoxing.us/tags/Random-Thoughts/"/>
</entry>
<entry>
<title>Deploy Mailman 3 on AWS Using Docker</title>
<link href="https://xiaoxing.us/2018/01/02/Deploy-Mailman-3-on-AWS-using-Docker/"/>
<id>https://xiaoxing.us/2018/01/02/Deploy-Mailman-3-on-AWS-using-Docker/</id>
<published>2018-01-01T18:22:12.000Z</published>
<updated>2018-01-30T16:03:12.038Z</updated>
<content type="html"><![CDATA[<p>Update Jan 2, 2018: I believe that this article has covered most components you need. If you have any problem, you're welcomed to contact me (tho I am not a professional guy) at... you can find my contact :)</p><p>Docker is now a hot topic, which is an open platform for developers and sysadmins to build, ship, and run distributed applications. It is good if you want to isolate different app environments.</p><p>Another topic today, Mailman, is a free software for managiing mailing list. It is a GNU project and it offers a good interface. In this article, I would like to introduce how to use Docker to deploy Mailman 3 on AWS, with Postfix and Amazon SES.</p><p>In this tutorial, I will assume that you are using macOS or Linux, which has an embedded OpenSSH tool. If you are using Windows 10, you may use the Windows Subsystem for Linux. For more information on the subsystem, please refer to <a href="https://msdn.microsoft.com/en-us/commandline/wsl/install-win10" target="_blank" rel="noopener">MSDN - Windows 10 Installation Guide</a> .</p><h1>Initialize a new EC2 Instance</h1><p>Before we go into the EC2 part, there remains a question — why not Elastic Container Service? One simple answer is, we need to deploy images on one instance (to save resource). So, let's get started.</p><h2>Generate a SSH Key</h2><p>First you need a SSH keys. By default, Amazon EC2 instances only allow user to log in using Key-Based Authentication. SSH keys provide an easy and secure way of logging into your server with only a pair of public/private keys.</p><p>If you don't have one, you may create one on your computer.</p><ol><li>Run the command (replace the [email protected] with your main email address).</li></ol><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-keygen -t rsa -b 4096 -C <span class="string">"[email protected]"</span></span><br></pre></td></tr></table></figure></p><ol start="2"><li>When you're prompted to "Enter a file in which to save the key," press Enter. This accepts the default file location. Or you may choose your desired file location.</li><li>When you're prompted to "Enter passphrase (empty for no passphrase)", please enter one password you like. You need to remember the password since it is required to decrypt the secret key. You may leave it blank, though it will be a bit unsecure.</li></ol><p><img src="https://static.notion-static.com/e0d490aea5114b298e1c48833f84c244/Untitled" alt=""></p><h2>Add the New SSH Key to <code>ssh-agent</code></h2><p><code>ssh-agent</code> is a program to hold private keys used for public key authentication (RSA, DSA). You may need to add your newly-generated key to <code>ssh-agent</code> , to make sure it will be used later. Here are the steps:</p><ol><li>Start a new agent process in the background.</li></ol><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="built_in">eval</span> <span class="string">"<span class="variable">$(ssh-agent -s)</span>"</span></span><br></pre></td></tr></table></figure></p><ol start="2"><li>(For macOS Sierra / High Sierra users) You will need to modify your ~/.ssh/config file to automatically load keys into the ssh-agent and store passphrases in your keychain.</li></ol><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line">Host *</span><br><span class="line"> AddKeysToAgent yes</span><br><span class="line"> UseKeychain yes</span><br><span class="line"> IdentityFile ~/.ssh/id_rsa</span><br></pre></td></tr></table></figure></p><ol start="3"><li>Add your key to agent. Remember to replace ~/.ssh/id_rsa with where you place it.</li></ol><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">ssh-add -K ~/.ssh/id_rsa</span><br></pre></td></tr></table></figure></p><p><img src="https://static.notion-static.com/24f9896a829e4949b945c650f5448939/Untitled" alt=""></p><h2>Import the SSH Key on Amazon Platform</h2><p>Now you have your owned SSH keys, and you will need to import it so Amazon can recognize it.</p><p>Log into your <a href="https://console.aws.amazon.com/console/home" target="_blank" rel="noopener">AWS Console</a> , click the EC2 link to go to the <a href="https://console.aws.amazon.com/ec2/v2/home" target="_blank" rel="noopener">EC2 Console</a> . Here you need to choose one of the available regions of EC2. Since I live in China, I choose the <em>Asia Pacific (Tokyo)</em> region for better speed. You may choose based on your visitor origins.</p><p><img src="https://static.notion-static.com/34f50a4985ab47a5a93913ab9e1acf14/Untitled" alt=""></p><p>Click Network & Security - Key Pairs on left sidebar. You will see a "Import Key Pair" button on top. Here you may copy using <code>clipcopy</code> by</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">cat <where_is_your_public_key.pub> | clipcopy</span><br></pre></td></tr></table></figure></p><p>You will need to paste it in the popup window on AWS console.</p><h2>Launch a New Instance</h2><p>After you have imported the public key, go back to the Dashboard page. Then click the big blue button " <em>Launch Instance</em> ".</p><p><img src="https://static.notion-static.com/0145cbc2e7624bbabcd4f28fbaac5835/Untitled" alt=""></p><p>On the next page, you should choose an Amazon Machine Image (AMI) to run on the new EC2 Instance. An AMI is a template that contains the software configuration (operating system, application server, and applications) required to launch your instance. Here we will pick the Amazon Linux AMI, since it includes most we need.</p><p><img src="https://static.notion-static.com/d20cdf36ad294eafaf395b20eb86b6e8/Untitled" alt=""></p><p>Next, choose an Instance Type, which is a combination of CPU, memory, storage, and networking capacity. Here we choose the <code>t2.micro</code> which provides free tier, then click on the "Next: Configure Instance Details" button. <a href="https://aws.amazon.com/free/" target="_blank" rel="noopener">Learn more</a> about free usage.</p><p><img src="https://static.notion-static.com/cc011fef86b5453b971d1093fe036735/Untitled" alt=""></p><p>Let's keep the default settings of Instance Details and next. We use a 30 GB EBS since the free tier provides it:</p><p><img src="https://static.notion-static.com/7cf66fd77d624de4a78b2ccb47786d48/Untitled" alt=""></p><p>We don't need a tag yet, so leave it blank and next to configure Security Group. A security group is a set of firewall rules that control the traffic for the instance.</p><p>Here you need to add some rules:</p><ul><li>Allow SSH (TCP 22) traffic from your IP address</li><li>Allow all ICMP traffic from your IP address, to enable ping requests</li><li>Allow HTTPS and HTTP traffic (TCP 443 and 80)</li><li>Allow port 8000 for testing Mailman (TCP 8000)</li><li>Allow port 8024 for LMTP (TCP 8024)</li><li>Allow port 25 for SMTP (TCP 25)</li></ul><p>You can also give the new security group a fancy name, like "Mailman-Security-Group". Then click "Review and Launch".</p><p><img src="https://static.notion-static.com/4004c447f653413c8c27c74cd6ded8a1/Untitled" alt=""></p><p>In the Review page, you will see all the settings you have made before. Once you ensure they are ready, click "Launch" button. You will now be prompted of choosing your key pair. Still remember what we have done before? Choose that key, and Launch.</p><p><img src="https://static.notion-static.com/5debc8cc967d454a9b5a7db651f9c964/Untitled" alt=""></p><p>You can now view the instances and find your newly-created one after few-minute initialization.</p><h2>Allocate Elastic IP</h2><p>An Elastic IP address is a static IP address designed for dynamic cloud computing. An Elastic IP address is associated with your AWS account. With an Elastic IP address, you can mask the failure of an instance or software by rapidly remapping the address to another instance in your account. Read more about EIPs <a href="http://docs.aws.amazon.com/AWSEC2/latest/UserGuide/elastic-ip-addresses-eip.html" target="_blank" rel="noopener">here</a> .</p><p>In short, we need to ensure our mailing list service has minimal downtime. Once the instance is down, we may switch to another instance if needed. To do that, first go back to the EC2 Dashboard, and then choose Network & Security - Elastic IPs.</p><p><img src="https://static.notion-static.com/dc0f131dd4db4497865a25c687238ae9/Untitled" alt=""></p><p>CLick "Allocate new address" button, then "Allocate". You will now have a new IP. Remember it as <EIP>.</p><p>Then go back to Elastic IPs page. Choose the one you just get, then click Actions - Associate address.</p><p><img src="https://static.notion-static.com/5946e9d77ae043c7952ae287a16d1939/Untitled" alt=""></p><p>Here you need to associate the new IP to the new EC2 instance.</p><p><img src="https://static.notion-static.com/508be3f14dc24ca79c8ea117938e3bf3/Untitled" alt=""></p><h2>Try to Connect to the Instance & Update the System</h2><p>You now have your EC2 instance. Excited? Now let's connect to the instance via SSH.</p><p>The default username of the image we used (remember? Amazon Linux) is <code>ec2-user</code> , so we can connect using</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> ssh ec2-user@<EIP></span><br></pre></td></tr></table></figure></p><p>You may be prompted to enter the password of your key. It is what you have set before. Forget the password? Go back to the most beginning of this article, and restart the works.</p><p>You are now in control of a fully working Linux server. Let's first update the system to ensure security.</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo yum update -y</span><br></pre></td></tr></table></figure></p><p><img src="https://static.notion-static.com/66f1f55618bb430387771b8870be43bb/Untitled" alt=""></p><h1>Install Docker on the Instance</h1><p>The next step is to install Docker on your EC2 Instance. Go back to the SSH session we opened before, enter:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> sudo yum install -y docker</span><br><span class="line">> sudo service docker start</span><br></pre></td></tr></table></figure></p><p>Next, add the <code>ec2-user</code> to the <code>docker</code> group so you can execute Docker commands without using sudo:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo usermod -a -G docker ec2-user</span><br></pre></td></tr></table></figure></p><p>You need to log out and log back to make it take effect. Enter <code>exit</code> to log out then log back with <code>ssh</code> . If nothing goes wrong, type <code>docker info</code> and it will return information about the Docker installation.</p><p>Now we can test the Docker installation by running the <code>training/webapp</code> image:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> docker run -d -p 80:5000 training/webapp:latest python [app.py](http://app.py)</span><br></pre></td></tr></table></figure></p><p>Copy the last line, which is the ID of the container. Try to visit http://<EIP>, you should see a page saying "Hello World!". If so, congratulations, and we now need to stop the container by:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> docker rm <CONTAINER_ID> -f</span><br></pre></td></tr></table></figure></p><p>After we have Docker ready, we need to install Docker Compose. Compose is a tool for defining and running multi-container Docker applications. With Compose, you use a YAML file to configure your application’s services. Follow the steps:</p><ol><li>Check the newest Compose release number in the <a href="https://github.com/docker/compose/releases" target="_blank" rel="noopener">Compose repository release page on GitHub</a> . Up to Nov. 24, 2017, it was 1.17.1.</li><li>Run this command to download the Docker Compose, replace <code><NEWEST_COMPOSE_RELEASE></code> with the version you get:</li></ol><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo curl -L https://github.com/docker/compose/releases/download/<NEWEST_COMPOSE_RELEASE>/docker-compose-`uname -s`-`uname -m` -o /usr/<span class="built_in">local</span>/bin/docker-compose</span><br></pre></td></tr></table></figure></p><ol start="3"><li>Add executable permissions to the binary:</li></ol><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo chmod +x /usr/<span class="built_in">local</span>/bin/docker-compose</span><br></pre></td></tr></table></figure></p><ol start="4"><li>Install command-line completion (Check here if you use zsh):</li></ol><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> sudo curl -L https://raw.githubusercontent.com/docker/compose/<NEWEST_COMPOSE_RELEASE>/contrib/completion/bash/docker-compose -o /etc/bash_completion.d/docker-compose</span><br><span class="line">> <span class="built_in">source</span> ~/.bash_profile</span><br></pre></td></tr></table></figure></p><ol start="5"><li>Test the installation:</li></ol><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> docker-compose --version</span><br><span class="line">docker-compose version 1.17.1, build 6d101fb</span><br></pre></td></tr></table></figure></p><h1>DNS Setting</h1><p>Now you have your instance, but before we head to the mailman part, let's bind a domain to the instance. The domain will be used as the address of mailman-web and the email address (the part after @).</p><p>Assuming we are using <a href="http://lists.example.com" target="_blank" rel="noopener">lists.example.com</a> as the domain, you should set a <code>A</code> DNS record of <code>lists.example.com</code> to the Elastic IP, then a <code>MX</code> record of <code>lists.example.com</code> , also to the Elastic IP.</p><h1>Configure Amazon SES</h1><p>Email is a complicated thing, especially when we are talking about delivery rate. It greatly depends on the reputation of your IP, your domain, and your contents. To ease a little burden, we will use Amazon SES here. Amazon SES, short for Amazon Simple Email Service, enables you to send and receive email using a reliable and scalable email platform.</p><h2>Verify Your Domain</h2><p>SES is also a region-based service (like EC2), but it is not available in Asia Pacific (Tokyo) yet, and therefore we choose US-East-1 (US East (N. Virginia)) as example here.</p><p>Let's navigate to the <a href="https://console.aws.amazon.com/ses/home?region=us-east-1" target="_blank" rel="noopener">SES Management Console</a> . Here you will see some introduction to SES, and a sidebar indicating all features you can use. But before we can send emails through SES, we need to verify our domain.</p><p>Click the "Identity Management - Domains", and "Verify a New Domain" in the right panel. In the modal window, enter the domain you set before ( <code>lists.example.com</code> here), and remember to select "Generate DKIM Settings".</p><p>What is DKIM? DomainKeys Identified Mail (DKIM) provides proof that the email you send originates from your domain and is authentic. It is a way to increase delivery rate.</p><p><img src="https://static.notion-static.com/52c570c65a2b4225b20cf13be0a08753/Untitled" alt=""></p><p>After you enter the domain, click "Verify This Domain". A new modal window will show, with a bunch of DNS records you need to set. There is a "Download Record Set as CSV", and you can download it since in the modal window the names and values. Then you should go to your DNS provider, set the required records (Note: only Domain Verification Record and DKIM Record Set, since we don't need SES to receive emails).</p><p><img src="https://static.notion-static.com/d1406bc4a3b34d2195c2c8bc84f08126/Untitled" alt=""></p><p>All DNS records shall look like this (Screenshot from Cloudflare):</p><p><img src="https://static.notion-static.com/581346be6802463190395c6754512a26/Untitled" alt=""></p><p>If you successfully set all records, the "pending verification" will become a green "verified".</p><p><img src="https://static.notion-static.com/3b30869ea1cd4c2d9788500b945a7059/Untitled" alt=""></p><h2>Add a Verified Email Address</h2><p>Well, by default, all new accounts are in sandbox mode, which means you can only send emails to the email addresses that you have verified. Before we request a sending limit increase, we should fully test our system first. So, let's add a verified email address.</p><p>First go to "Identity Management - Email Addresses". Here you will see a "Verify a New Email Address". Yes, click it and enter your owned email address ( <code>[email protected]</code> here). Amazon will send a verification email and you need to open it and complete the verification process.</p><p><img src="https://static.notion-static.com/502d2e5eca9741ed85f613c5f3867fdf/Untitled" alt=""></p><p><img src="https://static.notion-static.com/f3d3eea5468e4ee1abd8d6674aacc3b1/Untitled" alt=""></p><h2>Obtain SMTP Credentials</h2><p>You need to obtain your SMTP user name and password in order to send email via mailman. The SMTP credentials are different from your AWS credentials. To obtain it, let's go back to the SES Management Console, and click the "Email Sending - SMTP Settings". You will see some instruction on the right.</p><p><img src="https://static.notion-static.com/78e43b7cffbf4ad784370d1e49bee5a0/Untitled" alt=""></p><p>It shows the SMTP server name, port and TLS settings. Now click the "Create My SMTP Credentials". YOu will be redirected to IAM Management Console, where you can create an IAM user for SMTP authentication with Amazon SES. Here a new username is predefined but you can use whatever you like. Let's make it <code>example-smtp</code> here. Then you will see this page:</p><p><img src="https://static.notion-static.com/bcae25d897ec4e47a91a347d565cbc64/Untitled" alt=""></p><p>As instructed, download the credentials which will be used later.</p><h1>Install Postfix & Configure It</h1><p>Now let's go back to the SSH session (if your session was closed, just re-open one).</p><p>To use Postfix, you need to first remove sendmail and install postfix.</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> sudo yum remove sendmail -y</span><br><span class="line">> sudo yum install postfix -y</span><br></pre></td></tr></table></figure></p><p>Then, edit the postfix main config file <code>/etc/postfix/main.cf</code> using any editor you like (for example, <code>nano</code> ). Add the following lines to the end of the file. Remember to replace email-smtp.us-west-1.amazonaws.com in the example above with the SMTP server name shown before.</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br></pre></td><td class="code"><pre><span class="line">relayhost = [email-smtp.us-east-1.amazonaws.com]:587</span><br><span class="line">smtp_sasl_auth_enable = yes</span><br><span class="line">smtp_sasl_security_options = noanonymous</span><br><span class="line">smtp_sasl_password_maps = <span class="built_in">hash</span>:/etc/postfix/sasl_passwd</span><br><span class="line">smtp_use_tls = yes</span><br><span class="line">smtp_tls_security_level = encrypt</span><br><span class="line">smtp_tls_note_starttls_offer = yes</span><br><span class="line">inet_protocols = ipv4</span><br><span class="line">inet_interfaces = localhost, 172.19.199.1</span><br></pre></td></tr></table></figure></p><p>Now, open the master.cf file.</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo nano /etc/postfix/master.cf</span><br></pre></td></tr></table></figure></p><p>Locate the following line <code>-o smtp_fallback_relay=</code> and comment it (by placing a # (hash) character at the beginning). Save and close it.</p><p><img src="https://static.notion-static.com/8816265496144fbf942172d2342bc2dd/Untitled" alt=""></p><p>Still remember the SMTP credentials? It is now time to use it. Open (or create) a new file <code>/etc/postfix/sasl_passwd</code> .</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">>sudo nano /etc/postfix/sasl_passwd</span><br></pre></td></tr></table></figure></p><p>Add the following line to the file. Replace the USERNAME and PASSWORD with the REAL information:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">[email-smtp.us-east-1.amazonaws.com]:587 USERNAME:PASSWORD</span><br></pre></td></tr></table></figure></p><p>Now create a hashmap database file containing the SMTP credentials by:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo postmap <span class="built_in">hash</span>:/etc/postfix/sasl_passwd</span><br></pre></td></tr></table></figure></p><p>The password files created are not encrypted, but you can use the system access control feature to restrict access:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> sudo chown root:root /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db</span><br><span class="line">> sudo chmod 0600 /etc/postfix/sasl_passwd /etc/postfix/sasl_passwd.db</span><br></pre></td></tr></table></figure></p><p>Tell Postfix where to find the CA certificate (needed to verify the Amazon SES server certificate).</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo postconf -e <span class="string">'smtp_tls_CAfile = /etc/ssl/certs/ca-bundle.crt'</span></span><br></pre></td></tr></table></figure></p><p>Restart the Postfix server:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo postfix stop; sudo postfix start</span><br></pre></td></tr></table></figure></p><p>Well, you have finished an important step! Now let's send a test email. Type the following line at the SSH session, remember to press Enter after each line, and replace From and recipient address with your real address (From address should be <any>@<your_domain> and recipient address ahould be your verified email address.</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line">> sendmail -f [email protected] [email protected]</span><br><span class="line">From: Sender Name <[email protected]></span><br><span class="line">Subject: Amazon SES Test</span><br><span class="line">This message was sent using Amazon SES.</span><br><span class="line">.</span><br></pre></td></tr></table></figure></p><p>Check the mailbox associated with the recipient address. If the email does not arrive, check your junk mail folder. If you still cannot locate the email, check your system's mail log (typically located at <code>/var/log/maillog</code> ) for more information.</p><h1>Getting Ready for Containers</h1><p>GNU Mailman 3 is actually a suite of softwares, including Mailman Core, Mailman Client, Postorius, and Hyperkitty. The normal installation is very complicated (I tried before. See my repo <a href="https://github.com/Yexiaoxing/mailman-on-aws" target="_blank" rel="noopener">here</a> ). But luckily, we can use Docker. Abhilash Raj maintains container images for Mailman 3, which you can use directly without having to go through all the steps to download dependencies and configuring Mailman.</p><p>To run the containers, we first need to clone the docker-mailman repo, which contains all docker compose files we need.</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> git <span class="built_in">clone</span> https://github.com/maxking/docker-mailman && <span class="built_in">cd</span> docker-mailman</span><br></pre></td></tr></table></figure></p><p>The default compose file do these things:</p><ul><li>Run a wsgi server using <code>[uwsgi](https://uwsgi-docs.readthedocs.io/en/latest/)</code> for the Mailman's Django based web frontend listening on <a href="http://172.19.199.3:8000/" target="_blank" rel="noopener">http://172.19.199.3:8000/</a> . It will run 2 worker processes with 4 threads each.</li><li>Run a PostgreSQL server with a default database, username and password as mentioned in the <code>docker-compose.yaml</code> .</li><li>Run mailman-core listening an LMTP server at <a href="http://172.19.199.2:8024/" target="_blank" rel="noopener">http://172.19.199.2:8024/</a> for messages from MTA.</li></ul><p>Before we can deploy the images, some common configuration should be set in <code>docker-compose.yaml</code> file.</p><h2>Mailman-Core</h2><p>These we need to change one variable:</p><ul><li><code>HYPERKITTY_API_KEY</code> : Hyperkitty's API Key, should be set to the same value as set for the mailman-core.</li></ul><p>The remaining three variables shall be keep default, if you are happy with PostgreSQL:</p><ul><li><code>DATABASE_URL</code> : URL of the database for the django to use. The standard docker-compose.yaml comes with it set to a postgres database, and to simplify we keep it default.</li><li><code>DATABASE_TYPE</code> and <code>DATABASE_CLASS</code> : The standard file is <code>postgres</code> , and we also keep it default.</li></ul><p>If you want to use a different DBMS, you need to change the three variables.</p><h2>Mailman-web</h2><p>These are the settings that you MUST change before deploying:</p><ul><li><code>SERVE_FROM_DOMAIN</code> : The domain name from which Django will be served. You should set it to the domain you are going to use, <code>lists.example.com</code> here.</li><li><code>HYPERKITTY_API_KEY</code> : Hyperkitty's API Key, should be set to the same value as set for the mailman-core.</li><li><code>MAILMAN_ADMIN_USER</code> : The username for the admin user to be created by default.</li><li><code>MAILMAN_ADMIN_EMAIL</code> : The email for the admin user to be created by default. Remember to use the verified email before.</li><li><code>SECRET_KEY</code> : Django's secret key, mainly used for signing cookies and others.</li></ul><h2>Sample Docker Compose Configure</h2><p>Please check <a href="https://gist.github.com/Yexiaoxing/833bfcc5d3e4e0c06a8b7f0bac7c4c57" target="_blank" rel="noopener">this gist</a> for a sample config. You had better <strong>not</strong> copy the config but edit it yourself.</p><h2>Create Folders for Later Use</h2><p>Sometimes we need to do some extra configuration directly with the Mailman application.</p><p>There are two configuration files on the host that interact directly with Mailman's settings. These files exist on the host running the containers and are imported at runtime in the containers.</p><ul><li><code>/opt/mailman/core/mailman-extra.cfg</code> : This is the configuration for Mailman Core and anything that you add here will be added to Core's configuration. You need to restart your mailman-core container for the changes in this file to take effect.</li><li><code>/opt/mailman/web/settings_local.py</code> : This is the Django configuration that is imported by the <a href="https://github.com/maxking/docker-mailman/blob/e551701580966b062f8f64ea09380c671fbffbfe/web/mailman-web/settings.py" target="_blank" rel="noopener">existing configuration</a> provided by the mailman-web container. To change or override any settings in Django, you need to edit this file.</li></ul><p>To make it work, we need to create the folder:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> sudo mkdir -p /opt/mailman/core</span><br><span class="line">> sudo mkdir -p /opt/mailman/web</span><br></pre></td></tr></table></figure></p><h2>MTA Configuration</h2><p>Add the following settings to postfix's main config <code>/etc/postfix/main.cf</code> :</p><p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br></pre></td><td class="code"><pre><span class="line"># Support the default VERP delimiter.</span><br><span class="line">recipient_delimiter = +</span><br><span class="line">unknown_local_recipient_reject_code = 550</span><br><span class="line">owner_request_special = no</span><br><span class="line"></span><br><span class="line">transport_maps =</span><br><span class="line"> regexp:/opt/mailman/core/var/data/postfix_lmtp</span><br><span class="line">local_recipient_maps =</span><br><span class="line"> regexp:/opt/mailman/core/var/data/postfix_lmtp</span><br><span class="line">relay_domains =</span><br><span class="line"> regexp:/opt/mailman/core/var/data/postfix_domains</span><br></pre></td></tr></table></figure></p><p>Reload the Postfix by <code>sudo postfix reload</code> .</p><p>Then we need to configure Mailman to use Postfix. Add the following lines to /opt/mailman/core/mailman-extra.cfg:</p><p><figure class="highlight plain"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br></pre></td><td class="code"><pre><span class="line">[mta]</span><br><span class="line">incoming: mailman.mta.postfix.LMTP</span><br><span class="line">outgoing: mailman.mta.deliver.deliver</span><br><span class="line">lmtp_host: 172.19.199.2</span><br><span class="line">lmtp_port: 8024</span><br><span class="line">smtp_host: 172.19.199.1</span><br><span class="line">smtp_port: 25</span><br><span class="line">configuration: /etc/postfix-mailman.cfg</span><br></pre></td></tr></table></figure></p><p>Finally, we need to set the default Email setting of mailman-web by creating a file named <code>/opt/mailman/web/settings_local.py</code> and fill:</p><p><figure class="highlight python"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br></pre></td><td class="code"><pre><span class="line">USE_SSL = <span class="keyword">False</span></span><br><span class="line">EMAIL_BACKEND = <span class="string">'django.core.mail.backends.smtp.EmailBackend'</span></span><br><span class="line">EMAIL_HOST = <span class="string">'172.19.199.1'</span></span><br><span class="line">EMAIL_PORT = <span class="number">25</span></span><br><span class="line">DEFAULT_FROM_EMAIL = <span class="string">"lists@<your_domain>"</span></span><br><span class="line">SERVER_EMAIL = <span class="string">"lists@<your_domain>"</span></span><br></pre></td></tr></table></figure></p><ul><li><code>DEFAULT_FROM_EMAIL</code> : This is the default address that used used as the FROM header in all the emails from your installation.</li><li><code>SERVER_EMAIL</code> : This is the address from which the errors emails will be sent to you.</li></ul><h1>Run the Docker Containers</h1><p>OK. You are now ready to run the containers. Go into the <code>docker-mailman</code> folder and run:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> docker-compose up -d</span><br></pre></td></tr></table></figure></p><p>Docker will download all necessary images and run a container for you. What you need to do is to wait.</p><p>After the command runs, test if the service is running:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> curl http://172.19.199.3:8000/postorius/lists/</span><br></pre></td></tr></table></figure></p><p>If you see a bunch of HTML elements, you are done with containers.</p><h1>Install Nginx & Configure it</h1><p>It is advisable to run your Django (interfaced through WSGI server) through an actual web server in production for better performance. Here we use nginx, an HTTP and reverse proxy sever. It has been supporting many big sites such as Alibaba (which use a fork of nginx, called tengine).</p><h2>Install nginx</h2><p>One single command:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line">> sudo yum install nginx-all-modules -y</span><br><span class="line">> sudo service nginx start</span><br></pre></td></tr></table></figure></p><p>Then try to visit http://<your_domain>. you should see a <strong>Welcome to nginx on the Amazon Linux AMI!</strong> page.</p><p><img src="https://static.notion-static.com/c672f2dd45094abbbb2f3e3acb972c30/Untitled" alt=""></p><h2>Configure nginx</h2><p>Create a new file in <code>/etc/nginx/conf.d/</code> and name it with <code><your_domain>.conf</code> .</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo nano `/etc/nginx/conf.d/<your_domain>.conf`</span><br></pre></td></tr></table></figure></p><p>Fill in the following content:</p><p><figure class="highlight nginx"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br></pre></td><td class="code"><pre><span class="line"><span class="section">server</span> {</span><br><span class="line"> <span class="attribute">listen</span> <span class="number">80</span>;</span><br><span class="line"> <span class="attribute">server_name</span> `<your_domain>`;</span><br><span class="line"></span><br><span class="line"> <span class="attribute">location</span> /static/ {</span><br><span class="line"> <span class="attribute">alias</span> /opt/mailman/web/static/;</span><br><span class="line"> }</span><br><span class="line"></span><br><span class="line"> <span class="attribute">location</span> / {</span><br><span class="line"> <span class="attribute">include</span> uwsgi_params;</span><br><span class="line"> <span class="attribute">uwsgi_pass</span> <span class="number">172.19.199.3:8080</span>;</span><br><span class="line"> <span class="attribute">uwsgi_read_timeout</span> <span class="number">300</span>;</span><br><span class="line"> }</span><br><span class="line">}</span><br></pre></td></tr></table></figure></p><p>Then check if there is any error in config:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line">> sudo nginx -t</span><br><span class="line">nginx: the configuration file /etc/nginx/nginx.conf syntax is ok</span><br><span class="line">nginx: configuration file /etc/nginx/nginx.conf <span class="built_in">test</span> is successful</span><br></pre></td></tr></table></figure></p><p>We can now restart the nginx process:</p><p><figure class="highlight bash"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line">> sudo service nginx restart</span><br></pre></td></tr></table></figure></p><p>Now you can test Mailman using http://<your_domain>.</p><p><img src="https://static.notion-static.com/cbc47b05bab94bdf8e260d4d6f16e55c/Untitled" alt=""></p><h1>Obtain Password for Default Admin Account</h1><p>We have set the default admin username and email, but wait — where is the password? We need to obtain it by resetting password. Go to the mailman-web, click Sign In, click Forget Password and then enter the email address. You will receive an email with the resetting link. Follow the link to set the password.</p><p>You can now enjoy the Mailman 3.</p><h1>Further Step on SSL</h1><p>There are actually some further steps you can perform, for example, enable SSL. We won't discuss it here, since you only need to do:</p><ol><li>Obtain a SSL cert (from letsencrypt maybe)</li><li>Configure nginx to use the SSL</li><li>Remove the <code>USE_SSL = False</code> line in <code>/opt/mailman/web/settings_local.py</code></li></ol><h1>References</h1><ol><li><a href="https://help.github.com/articles/generating-a-new-ssh-key-and-adding-it-to-the-ssh-agent/#platform-mac" target="_blank" rel="noopener">GitHub - Generating a new SSH key and adding it to the ssh-agent</a></li><li><a href="https://asynchronous.in/docker-mailman/" target="_blank" rel="noopener">GNU Mailman 3 Deployment with Docker</a></li><li><a href="https://www.ybrikman.com/writing/2015/11/11/running-docker-aws-ground-up/" target="_blank" rel="noopener">Running Docker on AWS from the ground up</a></li><li><a href="http://docs.aws.amazon.com/ses/latest/DeveloperGuide/postfix.html" target="_blank" rel="noopener">Integrating Amazon SES with Postfix - AWS Documentation</a></li><li><a href="https://github.com/Yexiaoxing/mailman-on-aws" target="_blank" rel="noopener">Way to deploy Mailman 3 on AWS (My Repo)</a></li></ol>]]></content>
<summary type="html">
<p>Update Jan 2, 2018: I believe that this article has covered most components you need. If you have any problem, you're welcomed to contact
</summary>
<category term="Tutorials" scheme="https://xiaoxing.us/categories/Tutorials/"/>
<category term="Tutorials" scheme="https://xiaoxing.us/tags/Tutorials/"/>
<category term="docker" scheme="https://xiaoxing.us/tags/docker/"/>
<category term="mailman" scheme="https://xiaoxing.us/tags/mailman/"/>
<category term="aws" scheme="https://xiaoxing.us/tags/aws/"/>
</entry>
<entry>
<title>From 0 to 1: Build Your Blog Using Hexo</title>
<link href="https://xiaoxing.us/2017/11/19/From-0-to-1-Build-Your-Blog-using-Hexo/"/>
<id>https://xiaoxing.us/2017/11/19/From-0-to-1-Build-Your-Blog-using-Hexo/</id>
<published>2017-11-18T18:13:50.000Z</published>
<updated>2018-01-30T16:03:08.616Z</updated>
<content type="html"><![CDATA[<p>Want to have a place to save your ideas? You may need a blog. But the question comes, what kind of blogging software do you need?</p><p>I have tried many blogs, such as WordPress and Ghost. They both require to be installed on a server but I don't want to maintain a server (too lazy). So I come to Hexo, a static blog framework.</p><p>In this blog, I will mark down some important steps to set up a Hexo instance locally and to deploy it on GitHub Pages (possibly with CloudFlare or Netlify in next post), with the assumption of using a newly-installed macOS High Sierra.</p><h2>Install Packages</h2><h3>Install Homebrew</h3><p>Homebrew is a package manager for macOS. It will simplify many things such as finding packages and installing dependencies. Its official website is <a href="https://brew.sh" target="_blank" rel="noopener">https://brew.sh</a> .</p><p>The installation is very simple -- just paste this line at a Terminal prompt:</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> /usr/bin/ruby -e <span class="string">"<span class="variable">$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)</span>"</span></span></span><br></pre></td></tr></table></figure></p><p>It will also install Command Line Tools (CLT) for Xcode. This is required for compiling source codes.</p><p>After installing homebrew, we can run <code>brew doctor</code> to see if it is successfully installed and able to use.</p><h3>Check if Git is installed</h3><p>To make sure git is installed, we can run <code>command -v git</code> . If it doesn't complain that "command not found", things are fine.</p><p>If, unfortunately, it complains, check if Homebrew is successfully installed, and try <code>brew install git</code> to see if it can fix.</p><h3>Install Node.JS</h3><p>Since Hexo itself is a Node.js package, we will need to install Node.js first. Node.js itself updates very frequently, and the Hexo recommends using NVM.</p><p>NVM, short for <em>Node Version Manager</em> , is a script to manage Node.js versions. It can also be installed using a single line:</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> curl -o- https://raw.githubusercontent.com/creationix/nvm/v0.33.6/install.sh | bash</span></span><br></pre></td></tr></table></figure></p><p>(Note: Please check <a href="https://github.com/creationix/nvm" target="_blank" rel="noopener">https://github.com/creationix/nvm</a> to see if there is any update to NVM install script.)</p><p>Once NVM is installed, restart the Terminal then install a stable version of Node.js:</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> nvm install stable</span></span><br></pre></td></tr></table></figure></p><h3>Install Hexo</h3><p>You are finally here. Just install Hexo with npm:</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> npm install -g hexo-cli</span></span><br></pre></td></tr></table></figure></p><p>It will install a global instance of Hexo in your home directory.</p><h3>Use a Mirror for npm (Maybe for Chinese Users Only)</h3><p>Emmm... As we all know, the network in China is undergoing some difficulties. If you fail to fetch packages from the official registry (registry.npmjs.org) using NPM, you may try to use one of the mirrors in China.</p><p>Here, I recommend you to use the Taonpm (Taobao NPM Mirror). This is run by Alibaba so the speed and availability can be guaranteed.</p><p>There are many ways to use it. For example, use the smart-npm package instead of npm, by running <code>npm install --global smart-npm --registry=https://registry.npm.taobao.org/</code> . Or alias a new command:</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">alias</span> cnpm=<span class="string">"npm --registry=https://registry.npm.taobao.org \</span></span></span><br><span class="line">--cache=$HOME/.npm/.cache/cnpm \</span><br><span class="line">--disturl=https://npm.taobao.org/dist \</span><br><span class="line">--userconfig=$HOME/.cnpmrc"</span><br></pre></td></tr></table></figure></p><p>(Reference: <a href="http://www.uedbox.com/npm-install-slow-solution/" target="_blank" rel="noopener">http://www.uedbox.com/npm-install-slow-solution/</a> )</p><h2>Initialize Your Blog Locally</h2><p>Now you have installed Hexo, it is time to initialize Hexo. Simply run it (replacing</p><p><folder> with your desired target):</folder></p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> hexo init <folder></span></span><br><span class="line"><span class="meta">$</span><span class="bash"> <span class="built_in">cd</span> <folder></span></span><br></pre></td></tr></table></figure></p><p>This creates a basic project folder, which looks like:</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br></pre></td><td class="code"><pre><span class="line">\_config.yml # Site configuration file</span><br><span class="line">package-lock.json # You may see this file which is used by npm</span><br><span class="line">package.json # Application dependencies</span><br><span class="line">node_modules # Here store Node.js Modules</span><br><span class="line">scaffolds # When you create a new post, Hexo bases the new file on the scaffold</span><br><span class="line">source # Where site contents locate</span><br><span class="line">themes # Theme folder for static website generation</span><br></pre></td></tr></table></figure></p><h3>Configure Your New Blog</h3><p>You are having a fresh Hexo instance. Why not customize it? You can modify most site settings in <code>_config.yml</code> .</p><p>Please refer to <a href="https://hexo.io/docs/configuration.html" target="_blank" rel="noopener">https://hexo.io/docs/configuration.html</a> for available settings. Here I would like to mention some important</p><p><strong>Site:</strong> Title, subtitle, description, author, language, timezone</p><p><strong>URL:</strong> url, root, permalink</p><h2>How About... Start Writing?</h2><p>No one will read an empty blog, right? So, let's start writing! To create a new post or a new page, just run the command:</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> hexo new [layout] <title></span></span><br></pre></td></tr></table></figure></p><p>There are three layouts available by default, namely <code>post</code> , <code>page</code> , and <code>draft</code> . If you don't specify, <code>post</code> layout will be used.</p><p>Also, remember to quote your title if it contains spaces or special characters!</p><p>You may see that there is a special layout: <code>draft</code> . Posts initialized with this layout will not be displayed by default and you can use <code>publish</code> command to move drafts to post folder.</p><p>After running the command, Hexo will build a new file based on the corresponding file in <code>scaffolds</code> file. Yes -- you can add your own!</p><p>By default, the generated filename will use the post title. If you want to have a different one, consider editing the setting <code>new_post_name</code> . For more information, please read <a href="https://hexo.io/docs/writing.html" target="_blank" rel="noopener">https://hexo.io/docs/writing.html</a> .</p><h3>Markdown</h3><p>Hexo uses Markdown in the content. What is Markdown?</p><p><blockquote><p>Markdown is a lightweight markup language with plain text formatting syntax. It is designed so that it can be converted to HTML and many other formats using a tool by the same name.</p><footer><strong>Wikipedia <https: en.wikipedia.org="" wiki="" markdown=""> Markdown</https:></strong></footer></blockquote></p><p>It has a very simple but powerful syntax.</p><p><figure class="highlight markdown"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br><span class="line">6</span><br><span class="line">7</span><br><span class="line">8</span><br><span class="line">9</span><br><span class="line">10</span><br><span class="line">11</span><br><span class="line">12</span><br><span class="line">13</span><br><span class="line">14</span><br><span class="line">15</span><br><span class="line">16</span><br><span class="line">17</span><br><span class="line">18</span><br><span class="line">19</span><br><span class="line">20</span><br><span class="line">21</span><br><span class="line">22</span><br><span class="line">23</span><br><span class="line">24</span><br><span class="line">25</span><br><span class="line">26</span><br><span class="line">27</span><br><span class="line">28</span><br><span class="line">29</span><br><span class="line">30</span><br><span class="line">31</span><br></pre></td><td class="code"><pre><span class="line"><span class="section"># Heading</span></span><br><span class="line"></span><br><span class="line"><span class="section">### Sub-heading</span></span><br><span class="line"></span><br><span class="line"><span class="section">#### Another deeper heading</span></span><br><span class="line"></span><br><span class="line">Paragraphs are separated</span><br><span class="line">by a blank line.</span><br><span class="line"></span><br><span class="line">Two spaces at the end of a line leave a</span><br><span class="line">line break.</span><br><span class="line"></span><br><span class="line">Text attributes <span class="emphasis">_italic_</span>, <span class="emphasis">*italic*</span>, <span class="strong">__bold__</span>, <span class="strong">**bold**</span>, <span class="code">`monospace`</span>.</span><br><span class="line"></span><br><span class="line">Horizontal rule:</span><br><span class="line"></span><br><span class="line">---</span><br><span class="line"></span><br><span class="line">Bullet list:</span><br><span class="line"></span><br><span class="line"> * apples</span><br><span class="line"> * oranges</span><br><span class="line"> * pears</span><br><span class="line"></span><br><span class="line">Numbered list:</span><br><span class="line"></span><br><span class="line"> 1\. apples</span><br><span class="line"> 2\. oranges</span><br><span class="line"> 3\. pears</span><br><span class="line"></span><br><span class="line">A [<span class="string">link</span>](<span class="link">http://example.com</span>).</span><br></pre></td></tr></table></figure></p><h3>Tag Plugins</h3><p>Hexo provides a useful way for you to quickly add specific content to the posts. For more information, please refer to <a href="https://hexo.io/docs/tag-plugins.html#Code-Block" target="_blank" rel="noopener">https://hexo.io/docs/tag-plugins.html</a> .</p><h3>Front-matter</h3><p>Each post has its own style. You can customize settings for each post in front-matter. Front-matter is a block of YAML or JSON at the beginning of the file, terminated by three dashes when written in YAML or three semicolons when written in JSON.</p><p>YAML:</p><p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">title:</span> <span class="string">Hello</span> <span class="string">World</span></span><br><span class="line"><span class="attr">date:</span> <span class="number">2013</span><span class="string">/7/13</span> <span class="number">20</span><span class="string">:46:25</span></span><br><span class="line"><span class="meta">---</span></span><br></pre></td></tr></table></figure></p><p>JSON:</p><p><figure class="highlight javascript"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br></pre></td><td class="code"><pre><span class="line"><span class="string">"title"</span>: <span class="string">"Hello World"</span>,</span><br><span class="line"><span class="string">"date"</span>: <span class="string">"2013/7/13 20:46:25"</span></span><br><span class="line">;;;</span><br></pre></td></tr></table></figure></p><p>There are various settings available, like title, date, updated date, categories, and tags.</p><p>Posts are supporting categories and tags. Please read <a href="https://hexo.io/docs/front-matter.html" target="_blank" rel="noopener">https://hexo.io/docs/front-matter.html</a> .</p><h3>Images</h3><p>Want to insert some images? Hexo provides a different mechanism than Markdown itself. You may read <a href="https://hexo.io/docs/asset-folders.html" target="_blank" rel="noopener">https://hexo.io/docs/asset-folders.html</a> for more details.</p><h2>Take a Look At The Blog</h2><p>OK, now you have your owned writings. What about taking a look at them? Hexo provides an optional module of a server. To start using the server, you will first have to install hexo-server.</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> npm install hexo-server --save</span></span><br></pre></td></tr></table></figure></p><p>Remember to run it under the root of your blog. After installation, we can now run the server.</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> hexo server</span></span><br></pre></td></tr></table></figure></p><p>Your website will now run at <a href="http://localhost:4000" target="_blank" rel="noopener">http://localhost:4000</a> by default. When the server is running, Hexo will watch for file changes and update automatically so it's not necessary to manually restart the server.</p><h2>Generate A Static Site</h2><p>Well, what if you don't want to run another program to serve your website, instead of using Nginx to host static files? You can actually generate a static one! In Hexo, it can be done in a simple way.</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> hexo generate</span></span><br></pre></td></tr></table></figure></p><p>Then, everything you need is now in <code>public/</code> folder. Open <code>public/index.html</code> to see. So fantastic.</p><p>Wait, why my website becomes a bunch of plaintexts? It is because some browsers don't allow you to load local stylesheets and Javascript. But, no worry. Don't forget that we will push to GitHub Pages later.</p><h3>Watch File Changes</h3><p>You know, it is very annoying to run the generator every time we change any file. Hexo can watch for file changes and regenerate files immediately by comparing the SHA1 checksum. Just run this:</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> hexo generate --watch</span></span><br></pre></td></tr></table></figure></p><p>No pain.</p><h2>Themes</h2><p>Don't like the default look of your blog? There are hundreds of themes available (well I don't count it). You can pick up one of your favorite themes and install it.</p><p>Here are the steps.</p><ol><li>Find a theme here: <a href="https://hexo.io/themes/" target="_blank" rel="noopener">https://hexo.io/themes/</a></li><li>Get the GitHub repo address of the theme. For example, I will use <a href="https://github.com/Ben02/hexo-theme-Anatole" target="_blank" rel="noopener">https://github.com/Ben02/hexo-theme-Anatole</a> .</li><li>Clone it to <code>themes/</code> folder by <code>git clone https://github.com/Ben02/hexo-theme-Anatole.git themes/anatole</code></li><li>Install required plugins (if stated in the theme description)</li><li>Update <code>_config.yml</code> file. You will see a <code>theme</code> configuration. Change the value to the folder name that contains your theme ( <code>anatole</code> here).</li><li>Re-generate your site and take a look.</li></ol><h2>Deploy to GitHub</h2><p>It's now time to publish your site! Excited?</p><p>In this example, we will use GitHub Pages. Why?</p><p><blockquote><p>GitHub Pages is designed to host your personal, organization, or project pages directly from a GitHub repository.</p><footer><strong>GitHub Help <https: help.github.com="" articles="" what-is-github-pages=""> What is GitHub Pages?</https:></strong></footer></blockquote></p><p>Well, it is free and stable, why not? Let's get started.</p><p>(What? You know nothing about Git and GitHub? Google it.)</p><p>First, go to GitHub and <a href="https://github.com/new" target="_blank" rel="noopener">create a new repository</a> named <em>username.github.io</em> . This will be your future blog space.</p><p>Second, install hexo-deployer-git. Yes Hexo itself doesn't provide it (to keep it simple).</p><p><figure class="highlight shell"><table><tr><td class="gutter"><pre><span class="line">1</span><br></pre></td><td class="code"><pre><span class="line"><span class="meta">$</span><span class="bash"> npm install hexo-deployer-git --save</span></span><br></pre></td></tr></table></figure></p><p>Then, add some settings to your <code>_config.yml</code> :</p><p><figure class="highlight yaml"><table><tr><td class="gutter"><pre><span class="line">1</span><br><span class="line">2</span><br><span class="line">3</span><br><span class="line">4</span><br><span class="line">5</span><br></pre></td><td class="code"><pre><span class="line"><span class="attr">deploy:</span></span><br><span class="line"><span class="attr"> type:</span> <span class="string">git</span></span><br><span class="line"><span class="attr"> repo:</span> <span class="string"><repository</span> <span class="string">url,</span> <span class="string">copied</span> <span class="string">from</span> <span class="string">GitHub></span></span><br><span class="line"><span class="attr"> branch:</span> <span class="string">[branch]</span></span><br><span class="line"><span class="attr"> message:</span> <span class="string">[message]</span></span><br></pre></td></tr></table></figure></p><p>Last, run <code>hexo deploy</code> . If nothing goes wrong, you can navigate to http://</p><p><username>.github.io to view your website!</username></p><h3>Bind Your Owned Domain to GitHub Pages</h3><p>What? You have your owned domain and you want to bind it to your new blog? Of course, it can be done easily.</p><p>First, you need to create a new file called <code>CNAME</code> under <code>source/</code> folder, with the content of your desired domain (including subdomains.</p><p>Second, set the DNS record of your domain, CNAME it to <code>USERNAME.github.io</code> .</p><p>Third, run <code>hexo clean</code> then deploy again.</p><p>Finally, test your new custom domain.</p><p>Please be noted that, if you want to use an APEX domain, you need to follow the instruction here: <a href="https://help.github.com/articles/setting-up-an-apex-domain/" target="_blank" rel="noopener">https://help.github.com/articles/setting-up-an-apex-domain/</a>.</p><h2>References</h2><p>Hexo itself actually provides some document here: <a href="https://hexo.io/docs/index.html" target="_blank" rel="noopener">https://hexo.io/docs/index.html</a>. Please read it if you want to know more.</p>]]></content>
<summary type="html">
<p>Want to have a place to save your ideas? You may need a blog. But the question comes, what kind of blogging software do you need?</p>
<p>
</summary>
<category term="Tutorials" scheme="https://xiaoxing.us/categories/Tutorials/"/>
<category term="Installation" scheme="https://xiaoxing.us/tags/Installation/"/>
<category term="Hexo" scheme="https://xiaoxing.us/tags/Hexo/"/>
</entry>
</feed>