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