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