small doc update
[distro-setup] / phabricator-setup
1 #!/bin/bash -l
2 # Copyright (C) 2016 Ian Kelling
3
4 # Licensed under the Apache License, Version 2.0 (the "License");
5 # you may not use this file except in compliance with the License.
6 # You may obtain a copy of the License at
7
8 # http://www.apache.org/licenses/LICENSE-2.0
9
10 # Unless required by applicable law or agreed to in writing, software
11 # distributed under the License is distributed on an "AS IS" BASIS,
12 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 # See the License for the specific language governing permissions and
14 # limitations under the License.
15
16
17
18 # Automated phabricator setup. Not currently using it,
19 # but it worked last time I tried it.
20
21 set -eE -o pipefail
22 trap 'echo "$0:$LINENO:error: \"$BASH_COMMAND\" returned $?"' ERR
23
24 set -x
25
26
27 # lj is test server
28 case $HOSTNAME in
29 lj)
30 domain=phab.iank.bid
31 alt_domain=fastmail.wiki
32 ;;
33 lk)
34 domain=phab.iankelling.org
35 alt_domain=iankellingusercontent.org
36 ;;
37 esac
38
39
40 pass=`cat /p/c/machine_specific/$HOSTNAME/phabricator_admin`
41 webroot=/usr/share/phabricator/webroot
42 user=iank
43 name="Ian Kelling"
44 email=ian@iankelling.org
45 ssh_port=222
46
47 fbin() { bin=$1; shift; sudo /usr/share/phabricator/bin/$bin "$@"; }
48 fsetd() { fbin config set --database "$@"; }
49
50 # phabricator complained about wanting arcanist first
51 pi arcanist/unstable mercurial
52
53 for x in /a/bin/bash_unpublished/*; do source $x; done
54
55 # duplicated in mediawiki setup. todo fix that.
56 s DEBIAN_FRONTEND=noninteractive pi mysql-server
57 cd # mysql_secure_installation writes some temp files to the current dir,
58 # so we need to make sure it's writable.
59 if echo exit|mysql -u root -p"$dbpass"; then
60 echo -e "$dbpass\nn\n\n\n\n" | mysql_secure_installation
61 else
62 echo -e "\n\n$dbpass\n$dbpass\n\n\n\n\n" | mysql_secure_installation
63 fi
64
65 mysql -u root -p$dbpass <<EOF
66 grant all privileges on \`phabricator\\_%\`.* to 'phabricator'@localhost identified by '$pass';
67 EOF
68
69 phab-sel() {
70 s debconf-set-selections<<EOF
71 phabricator phabricator/pwd_check password $pass
72 phabricator phabricator/phabricator_mysql_pwd password $pass
73 phabricator phabricator/webserver select None
74 phabricator phabricator/phabricator_mysql_user string phabricator
75 phabricator phabricator/mysql_host string localhost
76 # Domain name or subdomain name used by phabricator:
77 phabricator phabricator/domain_name string $domain
78 EOF
79 }
80 phab-sel
81
82 pi phabricator/unstable
83
84 # debian sets http, but we want https
85 s sed -i --follow-symlinks 's/http:/https:/' /usr/share/phabricator/conf/local/local.json
86
87
88 acme-tiny-wrapper $domain
89 acme-tiny-wrapper $alt_domain
90
91 for x in $domain $alt_domain; do
92 apache-site -r $webroot - $x <<EOF
93 RewriteEngine on
94 RewriteRule ^/rsrc/(.*) - [L,QSA]
95 RewriteRule ^/favicon.ico - [L,QSA]
96 RewriteRule ^/php5-fcgi - [L]
97 RewriteRule ^(.*)\$ /index.php?__path__=\$1 [B,L,QSA]
98 <Directory "$webroot">
99 Require all granted
100 </Directory>
101 EOF
102 done
103
104
105 # Before I figured out how to setup the admin in the script,
106 # this would limit the site to localhost,
107 # and access it through an ssh tunnel until its secure.
108 #phab-site -p 127.0.0.1:443
109
110 # settings are stored in conf/local/local.json.
111 # some settings could also be stored in the database with
112 # --database arg. database has higher priority than
113 # the config file.
114
115 # if you need to restart phabricator, just ser restart apache2
116 # https://secure.phabricator.com/book/phabricator/article/restarting/
117
118 # to reset things, you can do.
119 # fbin storage destroy; pu phabricator; phab-sel; pi phabricator/unstable
120 # # but under debian, prolly better to purge, cause db gets created on install
121
122
123 # On first run went to the website, registered manually, then
124 # went through the gui setup items to get the configuration below.
125
126
127 #expect "*"
128 #sleep 1
129
130 # expect's exits with 0 by default on timeout of an expect command.
131 # You can modify this, but it was simpler to use an irregular code to detect
132 # actual success.
133 sudo expect -d <<EOF
134 # The expect lines use shell type globbing. They are not actually
135 # needed, but they make the script likely to fail if the questions
136 # content changes drastically, and make the script self documenting.
137
138 # adds a short delay after each send for more reliable operation
139 # (reference: comment in any autoexpect generated script)
140 set force_conservative 0
141 spawn "/usr/share/phabricator/bin/accountadmin"
142 # If we've already set our user, detect different prompt and exit
143 # expect basics: when the last alternative matches, there is no need
144 # to specify an action, we just continue.
145 expect {
146 timeout {exit 1}
147 -nocase "enter a username" exit
148 -nocase "y/n"
149 }
150 send "y\r"
151 expect -nocase timeout {exit 1} "username"
152 send "$user\r"
153 expect -nocase timeout {exit 1} "create*y/n"
154 send "y\r"
155 expect -nocase timeout {exit 1} "name"
156 send "$name\r"
157 expect -nocase timeout {exit 1} "email"
158 send "$email\r"
159 expect -nocase timeout {exit 1} "password"
160 send "$pass\r"
161 expect -nocase timeout {exit 1} "bot"
162 send "n\r"
163 expect -nocase timeout {exit 1} "admin"
164 send "y\r"
165 expect -nocase timeout {exit 1} "save"
166 send "y\r"
167 expect eof
168 exit
169 EOF
170
171
172
173 # this tipped me over to using a debian package
174 # https://secure.phabricator.com/T4181
175
176 fsetd auth.require-approval false
177
178 # phabricator recommends going from 16 to at least 32
179 sudo sed -ri 's/(^\s*max_allowed_packet)[[:space:]=].*/\1 = 100M/' /etc/mysql/my.cnf
180
181
182 setini() {
183 key="$1" value="$2" section="$3" file="$4"
184 sudo sed -ri "/ *\[$section\]/,/^ *\[[^]]+\]/{/^\s*$key[[:space:]=]/d};/ *\[$section\]/a $key = $value" "$file"
185 }
186
187 setd() { setini "$@" mysqld /etc/mysql/my.cnf; }
188
189 # error instead of data corruption:
190 setd sql_mode STRICT_ALL_TABLES
191 setd ft_stopword_file /usr/share/phabricator/resources/sql/stopwords.txt
192 setd ft_min_word_len 3
193 # mysql full text search for word1 word2 will and them instead of or them:
194 setd ft_boolean_syntax "' |-><()~*:\"\"&^'"
195 # default is 128M. recommended starting point is 40% of ram.
196 setd innodb_buffer_pool_size 1600M
197
198 # this files stopwork, and min_word_len
199 mysql -u root -p$dbpass <<'EOF'
200 REPAIR TABLE phabricator_search.search_documentfield;
201 EOF
202
203 fsetd pygments.enabled true
204 fbin config set security.alternate-file-domain https://$alt_domain
205
206 setini opcache.validate_timestamps '"0"' opcache /etc/php5/apache2/php.ini
207 setini post_max_size 100M PHP /etc/php5/apache2/php.ini
208
209 fsetd metamta.default-address phabricator@$domain
210 fsetd metamta.domain $domain
211
212
213 ser restart mysql
214
215 # Not sure if this is needed. while developing this script, mysql went down
216 # for a bit and the daemons died.
217
218
219 # todo, setup inbound email:
220 # https://secure.phabricator.com/book/phabricator/article/configuring_inbound_email/
221
222
223 # https://secure.phabricator.com/book/phabricator/article/diffusion_hosting/
224 # unmatchable password, allows login only via ssh, sudo, etc.
225 # this is standard.
226 # I tried having no home dir, (-d /nonexistent),
227 # but I got an error message on test sshing,
228 sudo useradd -p '*' -m --system -s /bin/sh vcs || [[ $? == 9 ]]
229
230 # you'd think the debian package would set this. todo: check on a fresh
231 # machine
232 fbin config set phd.user phabricator
233 fbin config set diffusion.ssh-user vcs
234
235 option="ALL=(phabricator) SETENV: NOPASSWD:"
236 www_files=$(which git hg|sed ':a;N;s/\n/, /;ta')
237 vcs_files=$(which git git-upload-pack git-receive-pack hg|sed ':a;N;s/\n/, /;ta')
238 [[ $www_files && $vcs_files ]] || exit 1
239 www_files="$www_files, /usr/lib/git-core/git-http-backend"
240 sudo dd of=/etc/sudoers.d/phabricator <<EOF
241 www-data $option $www_files
242 vcs $option $vcs_files
243 EOF
244
245 # Found this due to red x in the ui after setting up a test repo.
246 # todo: debian package should do this for us. see also:
247 # https://phab.iank.bid/config/edit/environment.append-paths/
248 sudo lnf /usr/lib/git-core/git-http-backend /usr/share/phabricator/support/bin
249
250 fbin config set diffusion.allow-http-auth true
251
252 # couldn't find a really appropriate place for it. It needs parent dir
253 # permissions to be root:root.
254 file=/usr/share/phabricator-local-ssh-hook.sh
255 # from /usr/share/phabricator/resources/sshd/phabricator-ssh-hook.sh
256 sudo dd of=$file <<'EOF'
257 #!/bin/sh
258 # For debugging, you can temporarily do:
259 # exec >/tmp/plog 2>&1
260 # This script executes as the vcs user
261 if [ "$1" != vcs ]; then exit 1; fi
262 exec "/usr/share/phabricator/bin/ssh-auth" $@
263 EOF
264 sudo chmod 755 $file
265
266 sudo dd of=/etc/ssh/sshd_config.phabricator <<EOF
267 AuthorizedKeysCommand $file
268 AuthorizedKeysCommandUser vcs
269 AllowUsers vcs
270
271 Port $ssh_port
272 Protocol 2
273 PermitRootLogin no
274 AllowAgentForwarding no
275 AllowTcpForwarding no
276 PrintMotd no
277 PrintLastLog no
278 PasswordAuthentication no
279 AuthorizedKeysFile none
280
281 PidFile /var/run/sshd-phabricator.pid
282 EOF
283
284 sudo dd of=/etc/systemd/system/phabricator-ssh.service <<'EOF'
285 [Unit]
286 Description=OpenBSD Secure Shell server for phabricator repos
287 After=network.target auditd.service
288 ConditionPathExists=!/etc/ssh/sshd_not_to_be_run
289
290 [Service]
291 ExecStart=/usr/sbin/sshd -f /etc/ssh/sshd_config.phabricator
292 ExecReload=/bin/kill -HUP $MAINPID
293 KillMode=process
294 Restart=on-failure
295
296 [Install]
297 WantedBy=multi-user.target
298 EOF
299
300 sudo systemctl daemon-reload
301
302 # got this error upon ssh, figured out a solution.
303 # [2016-06-10 06:40:15] EXCEPTION: (AphrontInvalidCredentialsQueryException) #1045: Access denied for user 'root'@'localhost' (using password: NO) at [<phutil>/src/aphront/storage/connection/mysql/AphrontBaseMySQLDatabaseConnection.php:306]
304 # arcanist(), phabricator(), phutil()
305
306 s usermod -a -G vcs www-data
307 s usermod -a -G vcs ian
308 s usermod -a -G vcs phabricator
309 s chown root:vcs /usr/share/phabricator/conf/local/local.json
310 fbin config set diffusion.ssh-port $ssh_port
311
312 fsetd policy.allow-public true
313
314 sgo phabricator-ssh
315
316 ser restart apache2
317 sgo phabricator
318
319
320 # todo, finish next steps here:
321 # notably, backup/restore
322 # https://secure.phabricator.com/book/phabricator/article/configuration_guide/
323
324
325 fbin auth recover iank
326
327 cat <<EOF
328 # go to link above, then
329 # https://$domain/auth/config/new/
330 # and add username/pass auth provider.
331 EOF
332
333
334
335 # beginnings of automating those last manual steps:
336
337
338 # for setting the auto provider, we can use the api.
339 #arc set-config default https://$domain
340 #
341 # but first we have to generate an api key by getting
342 # https://phab.iank.bid/conduit/login/
343 # to do that, we've got to login to the url login.
344 # We've got to post to a url on the login page,
345 # then record 2 cookies: phuser and phsid
346 # It also does a 302 for us to do 2 more pages related to auth/login.
347
348 # we need to post to the right url (didn't record it, with these params)
349 #allowLogin:"1"
350 #allowRegistration:"1"
351 #allowLink:"1"
352 #allowUnlink:"1"
353
354
355 #Serve over HTTP
356 #
357 #
358 # phabricator/ $ ./bin/repository edit rT --as iank --local-path ...
359
360 #