GPG with Yubikey 4

0. Pre

Before you proceed, make sure you fully understand following jargons: open GPG, GPG master key and sub keys, Yubi Key by Yubico.
Reference info can be found at:

http://cfig.github.io/2015/09/22/GPG-usage/ describes basic operations of GPG
Yubikey 4, which can be bought at Amazon.
Others: https://lmy441900.github.io/security/yubikey/2016/09/10/about-yubikey-4.html

This guide has been tested on Debian(Jessie).

1. Set up Yubikey4 env for Debian

First, please read https://wiki.debian.org/Smartcards/YubiKey4 carefully.

# apt-get install scdaemon gnupg2 dirmngr

We need to enable normal user(not only root!) to use YubiKey4 on Debian by adding udev rules as /etc/udev/rules.d/99-yubikeys.rules

# YubiKey 4 OTP+U2F+CCID
SUBSYSTEMS=="usb", ATTRS{idVendor}=="1050", ATTRS{idProduct}=="0407", GROUP="plugdev", TAG+="uaccess"

Then reboot system to let it take effect. Verify smart card status:

$ gpg2 --card-status

2. Move sign/encrypt/authenticate subkeys to smartcard

What we should work on is always subkey. Master key is always stored at some safe airgapped media.
Assuming you have sign/encrypt/authenticate private subkeys locally.

$ gpg2 --edit-key $KEYID
$ toggle
gpg> key 1
gpg> keytocard

Finally verify the smart card status as:

$ gpg2 --card-status

We can see “Signature key”, “Encryption key”, “Authentication key” should have valid values.

3. Set up misc values for Yubikey4

After we push pubkey to server like this,

gpg --keyserver hkp://pgp.mit.edu --send-keys 1370401F

We can search our keys at:

http://pgp.mit.edu/pks/lookup?op=get&search=0xD6F140FF1370401F

Then we should edit our Yubikey4 as:

$ gpg2 --card-edit
admin
url
http://pgp.mit.edu/pks/lookup?op=get&search=0xD6F140FF1370401F
quit

4. Try out Yubikey4 on another machine:

Or if you are using the same machine for testing, you can delete all pub/priv keys manually before testing.

get pubkey from server
gpg2 --card-edit
fetch
quit
get private key stub
gpg2 --card-status
Verify key status
gpg2 -K
gpg2 -k

5. Using GPG for SSH login

I am using GnuPG 2.1.
Generate gpg-agent config

echo enable-ssh-support > ~/.gnupg/gpg-agent.conf

Add this to .bashrc, which will tell ssh to ask for gpg-agent:

#GPG
export GPG_TTY="$(tty)"
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
gpg-connect-agent updatestartuptty /bye
#GPG - END

Logout and login, check status:

ssh-add -l
ssh-add -L

Copy and paste the key to remote .ssh/authorized_keys
Then have a try with ‘ssh ‘.

6. misc references

https://demo.yubico.com/u2f.php

thinkPHP on apache and nginx

1.1 apache site config

add the following into /etc/apache2/sites-enabled/php_82.conf

<VirtualHost *:82>
    ServerAdmin webmaster@localhost
    DocumentRoot /home/spring/p2phunter_cn

    ErrorLog ${APACHE_LOG_DIR}/error.log
    CustomLog ${APACHE_LOG_DIR}/access.log combined

    <Directory "/home/spring/p2phunter_cn">
        Options Indexes FollowSymLinks MultiViews Includes ExecCGI
        AddHandler cgi-script .cgi
        AllowOverride all
        Require all granted
        AddType text/html .html
        AddOutputFilter INCLUDES .html
        DirectoryIndex index.php
    </Directory>
</VirtualHost>

1.2 apache2 behind nginx

needs to start apache2 with the same user as nginx.
Open /etc/apache2/envvars and set:

export APACHE_RUN_USER=nginx
export APACHE_RUN_GROUP=nginx

2.1 php site config

add .htaccess to php site root dir, this will handle url rewrite. See thinkphp help

<IfModule mod_rewrite.c>
 RewriteEngine on
 RewriteCond %{REQUEST_FILENAME} !-d
 RewriteCond %{REQUEST_FILENAME} !-f
 RewriteRule ^(.*)$ index.php?s=/$1 [QSA,PT,L]
</IfModule>

2.2 php-fpm behind apache2

If we “grep ‘user’ /etc/nginx/nginx.conf”, we found nginx is started as user ‘nginx’.
Let’s modify “/etc/php5/fpm/pool.d/www.conf" as this:

listen.owner = nginx
listen.group = nginx
listen.mode = 0660

Then restart php-fpm

service php5-fpm restart

Finally confirm the sock file has correct file attributes:

ls -l /var/run/php5-fpm.sock

jvm performance monitoring

I. tools

1. jps

check running jvm instances

jps -lvm

2. VisualVM (JVisualVM)

https://visualvm.github.io/ has latest tool. An alternative is the JVisualVM tool distributed with your JDK.

2.1 enable remote debug

Enable remote debugging, anonymous access

-Dcom.sun.management.jmxremote.port=8897 \
-Dcom.sun.management.jmxremote.authenticate=false \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=192.168.31.121

Enable remote debugging, password access

-Dcom.sun.management.jmxremote.port=8897 \
-Dcom.sun.management.jmxremote.password.file=jmx.passwd \
-Dcom.sun.management.jmxremote.ssl=false \
-Djava.rmi.server.hostname=192.168.31.121

Edit jmx.passwd file:

monitorRole good
controlRole bad

More documents available at: http://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html

3. jstatd

All-in-one script to start jstatd:

#!/bin/sh
set -x
policy=${HOME}/.jstatd.all.policy
[ -r ${policy} ] || cat >${policy} <<'POLICY'
grant codebase "file:${java.home}/../lib/tools.jar" {
  permission java.security.AllPermission;
};
POLICY

jstatd -J-Djava.security.policy=${policy}

With jstatd running, ‘jvisualvm’ can activate ‘Visual GC’ plugin.

4. jcmd

jcmd <PID> VM.command_line
jcmd <PID> VM.flags

5. jmap

jmap -dump:format=b,file=<name.hprof>
jmap -dump:live,file=<live_heap.bin>

For analyzing memory leaks just live objects are good enough.

II. Useful JVM flags

dump on OOME

-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/logs/heapdump

native memory tracking

Enable native memory tracking by

-XX:NativeMemoryTracking=summary

or

-XX:NativeMemoryTracking=detail

Then issue the following command:

jcmd <pid> VM.native_memory baseline

and then

jcmd <pid> VM.native_memory detail.diff

III. Appendix

Execute runnable jar with following wrapper

#!/bin/bash
if [ $# -ne 1 ]; then
    echo "Usage: ${0} <path_to_jar>"
    exit 1
fi

ts=`date +%Y.%m.%d.%H.%M.%S`
logfile="console_${ts}.log"
set -x
java \
    -Dcom.sun.management.jmxremote.port=8897 \
    -Dcom.sun.management.jmxremote.password.file=jmx.passwd \
    -Dcom.sun.management.jmxremote.ssl=false \
    -Djava.rmi.server.hostname=10.37.116.86 \
    -XX:+HeapDumpOnOutOfMemoryError \
    -XX:NativeMemoryTracking=detail \
    -jar $1 \
    >> ${logfile} 2>&1 \
    &
set +x
sleep 1
echo "console log written to ${logfile}"

Bring up Android A/B system (Part 2)

trouble shooting

With A/B system, previous mkdir/symlink may not work, in such case we need to create such folders/links at build time.

BOARD_ROOT_EXTRA_FOLDERS := customer_data
BOARD_ROOT_EXTRA_SYMLINKS := /customer_data:/customer

if you can not find the boot device

printk_all_partitions() from $linux/block/genhd.c can print a full list of all partitions, intended for places where the root filesystem can’t be mounted and thus to give the victim some idea of what went wrong.

[    1.993936] List of all partitions:
[    1.997553] 0100            8192 ram0  (driver?)
[    2.002335] b300         7471104 mmcblk0  driver: mmcblk
[    2.007837]   b301            1024 mmcblk0p1 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.015581]   b302            1024 mmcblk0p2 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.023317]   b303            7168 mmcblk0p3 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.031061]   b304            7168 mmcblk0p4 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.038804]   b305            8192 mmcblk0p5 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.054833]   b306            8192 mmcblk0p6 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.062570]   b307           16384 mmcblk0p7 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.070310]   b308           16384 mmcblk0p8 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.078052]   b309           16384 mmcblk0p9 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.085793]   b30a           16384 mmcblk0p10 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.093618]   b30b           16384 mmcblk0p11 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.101450]   b30c           16384 mmcblk0p12 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.109278]   b30d           16384 mmcblk0p13 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.117110]   b30e           16384 mmcblk0p14 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.124939]   b30f           16384 mmcblk0p15 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.132765]   b310           16384 mmcblk0p16 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.140596]   b311           16384 mmcblk0p17 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.148426]   b312           16384 mmcblk0p18 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.156256]   b313           32768 mmcblk0p19 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.164081]   103:00000      32768 mmcblk0p20 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.171911]   103:00001     950272 mmcblk0p21 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.179742]   103:00002     950272 mmcblk0p22 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.187573]   103:00003      16384 mmcblk0p23 b2285256-164b-4ab5-dcb9-699f7b7bb600
[    2.195404]   103:00004      16384 mmcblk0p24 b2285256-164b-4ab5-dcb9-699f7b7bb600

Supposing your /system partition resides on p21 of mmcblk0, your bootloader should set root=/dev/mmcblk0p21.

if you can start shell, but Android didn’t start, WTF?

You may need to parse your init.xx.rc, and check which stage you are at.
Android will be started in class “main” of init.

if you find BCB data is cleared unexpectedly, please blame Google …

There is “bootable/recovery/uncrypt/uncrypt.rc”, which will be put at “/system/etc/init/uncrypt.rc”, it will clear BCB on start up, which clears ‘active_slot’ too.

service clear-bcb /system/bin/uncrypt --clear-bcb
    class main
    socket uncrypt stream 600 system system
    disabled
    oneshot

But sadly, Android N 7.0 doesn’t have the right code to handle such cases. To fix this issue, you can either do some hacks to disable this BCB clear actions, or upgrade latest AOSP, which has defined “bootloader_message_ab” to match newer A/B styled Android.

bootloader_message struct

bootloader_message (1088 bytes)

char command[32]
char status[32]
char recovery[768]
char stage[32]
char slot_suffix[32]
char reserved[192]

BrilloSlotInfo (4 bytes)

uint8_t bootable : 1;
uint8_t reserved[3];

BrilloBootInfo (32 bytes)

char bootctrl_suffix[4];
uint8_t magic[3]; //"BCc"
uint8_t version;
uint8_t active_slot;
BrilloSlotInfo slot_info[2];
uint8_t reserved[15];

bootloader_message_ab struct

(2 KB) bootloader_message

char command[32]
char status[32]
char recovery[768]
char stage[32]
char reserved[1184]

(2 KB)

char slot_suffix[32]
char reserved[2016]

Bring up Android A/B system (Part 1)

1. Prepatation

Before you start, be sure to read Google’s official guide first: https://source.android.com/devices/tech/ota/ab_updates.html and https://source.android.com/devices/tech/ota/ab_implement.

This post will introduce a sample Android A/B system update implementation which stores information in /misc partition, similar as Intel reference product https://android.googlesource.com/platform/hardware/bsp/intel/+/android-7.0.0_r35/soc/common/bootctrl

You can also save such misc information in any other tamper-evident storage.

1.1 Requirement for kernel

Make sure your kernel support A/B features as described in the guide.

1.2 Requirement for bootloader

  • bootloader read active_slot from /misc partition(value is 0 or 1), then translates the value to _a or _b,

Newer android has updated the BCB data structure from bootloader_message to bootloader_message_ab.

bootloader_message_ab -> slot_suffix(BrilloBootInfo) -> active_slot
  • bootloader locates partitions for /system_a or /system_b as /dev/XX, assemble kernel command line, then load kernel from partition /boot_a or /boot_b.

Kernel command line should have this such info:

ro root=/dev/XX skip_initramfs
  • kernel boots up w/o ramdisk inside boot partition, instead it will run with rootfs at /dev/XX. fs_mgr then reads /misc for active_slot, and mounts /system_a or /system_b to /.

2. make the change on Android

2.1 update partition table

All partitions which need to support A/B must be named in the new style, like boot_a, boot_b, vendor_a, vendor_b, vendor1_a, vendor1_b etc.

2.2 update makefiles and config files

BoardConfig.mk

-BOARD_KERNEL_CMDLINE := root=/dev/ram0
+BOARD_KERNEL_CMDLINE := ro root=/dev/mmcblk0p18 skip_initramfs

-BOARD_RECOVERYIMAGE_PARTITION_SIZE := 33554432
-BOARD_CACHEIMAGE_PARTITION_SIZE := 536870912
-BOARD_CACHEIMAGE_FILE_SYSTEM_TYPE := ext4
-BOARD_USES_FULL_RECOVERY_IMAGE := true

/cache and /recovery is osbolete, remove then both.

fstab.{ro.hardware}

-/dev/block/by-name/system /system ext4 ro wait
+/dev/block/by-name/system /       ext4 ro,barrier=1,discard wait,slotselect
-/dev/block/by-name/cache  /cache  ext4 noatime,nosuid,nodev,rw  check

device.mk

AB_OTA_UPDATER := true
BOARD_BUILD_SYSTEM_ROOT_IMAGE := true
BOARD_USES_RECOVERY_AS_BOOT := true
TARGET_NO_RECOVERY := true

makefile won’t generate recovery.img, instead boot.img contains recovery mode ramdisk.

AB_OTA_PARTITIONS += \
    boot \
    system

boot.img and system.img have A/B slots.

PRODUCT_PACKAGES += \
    update_engine \
    update_engine_sideload

“update_engine” is a daemon manipulating background updates,

“update_engine_sideload “ is a static binary equivalent to update_engine daemon that installs an update from a local file directly instead of running in the background.

PRODUCT_PACKAGES_DEBUG += \
    update_engine_client

“update_engine_client” is update_engine console client

PRODUCT_PACKAGES += \
    update_verifier

“update_verifier” checks the integrity of the updated system and vendor partitions on the first boot post an A/B OTA update. It marks the current slot as having booted successfully if it passes the verification.

# bootctrl HAL
PRODUCT_PACKAGES += \
    bootctrl.default \
    bootctrl.$(TARGET_BOARD_PLATFORM)
    bootctl

bootctrl.$(TARGET_BOARD_PLATFORM) is bootctrl HAL, “bootctl” is Command-line wrapper for boot_control HAL. bootctrl.default is only a reference which should never appear in production images.

# A/B OTA post actions
PRODUCT_PACKAGES += cfigPostInstall
AB_OTA_POSTINSTALL_CONFIG += \
    RUN_POSTINSTALL_system=true \
    POSTINSTALL_PATH_system=bin/cfigPostInstall \
    FILESYSTEM_TYPE_system=ext4 \
    POSTINSTALL_OPTIONAL_system=true

# App compilation in background
PRODUCT_PACKAGES += otapreopt_script
AB_OTA_POSTINSTALL_CONFIG += \
  RUN_POSTINSTALL_system=true \
  POSTINSTALL_PATH_system=system/bin/otapreopt_script \
  FILESYSTEM_TYPE_system=ext4 \
  POSTINSTALL_OPTIONAL_system=true

3. output

With all the changes, you can get your production images and OTA packages with “make dist”.

I will explain the details of OTA packages later.

spring-session

1. spring-session for browswer (token in HttpSession)

Enable Redis HttpSession,

@EnableRedisHttpSession
public class HttpSessionConfig {
}

2. spring-session for REST (token in header)

Enable Redis HttpSession, and use HTTP headers to convey session info.

@EnableRedisHttpSession
public class HttpSessionConfig {
@Bean
public HttpSessionStrategy httpSessionStrategy() {
//use HTTP headers to convey the current session information instead of cookies
return new HeaderHttpSessionStrategy();
}
}

Enable Web Security

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication().withUser("admin").password("pwd").roles("USER");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.anyRequest().authenticated()
.and()
.requestCache()
.requestCache(new NullRequestCache())
.and()
.httpBasic();
}
}

build.gradle

compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-security")
compile("org.springframework.session:spring-session-data-redis")

operation w/o token will result in 401(UnAuth):

curl -v http://localhost:8080/

login with:

curl -v http://localhost:8080/ -u admin:pwd

resp will has header:

x-auth-token: 0dc1f6e1-c7f1-41ac-8ce2-32b6b3e57aa3

all later operations need to set “x-auth-token” in header

curl -v http://localhost:8080/ -H "x-auth-token: ${token}"

logout will invalidate the session

curl -v http://localhost:8080/logout -H "x-auth-token: ${token}"

3. class and packages

org.springframework.session

  • (C)HeaderHttpSessionStrategy
  • @EnableRedisHttpSession

org.springframework.security

  • @EnableWebSecurity
  • (C)WebSecurityConfigurerAdapter

org.springframework.web

  • @RestController
  • @RequestMapping

javax.servlet.http (inside spring-boot-starter-web)

  • (C)HttpSession

org.springframework.data.redis (needed by reflection, inside spring-boot-starter-redis or spring-session-data-redis)

  • (I) RedisSerializer

4. packages

“spring-boot-starter-redis” includes

\--- org.springframework.boot:spring-boot-starter-redis: -> 1.4.2.RELEASE
     +--- org.springframework.boot:spring-boot-starter:1.4.2.RELEASE
     +--- org.springframework.data:spring-data-redis:1.7.5.RELEASE
     \--- redis.clients:jedis:2.8.2

“spring-session” is atom package

\--- org.springframework.session:spring-session: -> 1.2.2.RELEASE

“spring-session-data-redis” includes

\--- org.springframework.session:spring-session-data-redis: -> 1.2.2.RELEASE
     +--- org.apache.commons:commons-pool2:2.4.2
     +--- org.springframework.data:spring-data-redis:1.7.1.RELEASE -> 1.7.5.RELEASE
     +--- org.springframework.session:spring-session:1.2.2.RELEASE
     \--- redis.clients:jedis:2.8.1 -> 2.8.2

nginx configuration examples

default http service

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;

    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }
}

https service

server {
    listen 443;
    server_name cfig.me;

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    ssl on;
    ssl_certificate 2017/213964558630897.pem;
    ssl_certificate_key 2017/213964558630897.key;
    ssl_session_timeout 5m;
    ssl_protocols SSLv3 TLSv1;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
    ssl_prefer_server_ciphers on;

    location / {
        try_files $uri $uri/ =404;
    }
}

reverse-proxy for localhost:8080

nginx handles https and redirects all requests to local service listening on 8080.

upstream api_node_js {
    server    127.0.0.1:8080;
}
server {
    listen 443;
    server_name api.cfig.me;

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    ssl on;
    ssl_certificate 2017_api_cfig_me/213972664770897.pem;
    ssl_certificate_key 2017_api_cfig_me/213972664770897.key;

    ssl_session_timeout 5m;
    ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
    ssl_ciphers AESGCM:ALL:!DH:!EXPORT:!RC4:+HIGH:!MEDIUM:!LOW:!aNULL:!eNULL;
    ssl_prefer_server_ciphers on;

    location / {
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header Host $http_host;
        proxy_set_header X-NginX-Proxy true;
        proxy_pass http://api_node_js;
        proxy_redirect off;
    }
}

‘proxy_set_header’ will change http headers passed to local 8080, ‘X-Real-IP’ and ‘X-Forwarded-For’ now has the real src IP as shown below:

file service

server {
    listen 4573 default_server;
    listen [::]:4573 default_server;
    server_name _;

    root /var/download;
    autoindex on;
    autoindex_exact_size on;
    autoindex_localtime on;

    index index.html index.htm index.nginx-debian.html;

    location / {
        try_files $uri $uri/ =404;
    }
}

https gerrit with basic http auth

server {
    listen 80;
    server_name g.cf1g.com;
    return    301 https://$server_name$request_uri;
}

server {
    listen 443;
    server_name g.cf1g.com;

    location / {
        auth_basic              "Gerrit 2.12";
        auth_basic_user_file    /etc/nginx/htpwd.conf;
        proxy_pass              http://localhost:8081;
        proxy_set_header        X-Forwarded-For $remote_addr;
        proxy_set_header        Host $host;
    }

    ssl on;
    ssl_certificate 2016/1_cf1g.com_bundle.crt;
    ssl_certificate_key 2016/cf1g.rsa;

    ssl_session_timeout 5m;

    ssl_protocols SSLv3 TLSv1;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
    ssl_prefer_server_ciphers on;
}

gradle-springboot

springboot use jetty instead of tomcat:

configurations {
compile.exclude module: 'spring-boot-starter-tomcat'
}

dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-jetty")
}

generate deployable war for jetty:

build.gradle

apply plugin: 'war'

WarApplication.java

import org.springframework.boot.web.support.SpringBootServletInitializer;
@SpringBootApplication
public class WarApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(WarApplication.class, args);
}

}

Gerrit notes


1. 安装

Download from https://www.gerritcodereview.com/

Install guide: https://gerrit-review.googlesource.com/Documentation/install.html

2. gerrit/nginx反向代理配置

反向代理结构 http://g.cf1g.com –(301)–> https://g.cf1g.com ==(auth)==>> proxy-http://127.0.0.1:8081

2.1 gerrit.config

httpd.listenUrl: proxy-https://127.0.0.1:8081/ 配置gerrit http只接受local 8081端口请求
sshd.listenAddress: *:29418 配置gerrit ssh接受所有29418端口请求

2.2 /etc/nginx/sites-available/gerrit

auth_basic_user_file: http密码文件
ssl_certificate: ssl证书, 相对于/etc/nginx/的路径
ssl_certificate_key: ssl私钥(RSA key), 相对于/etc/nginx/的路径

2.3 /etc/nginx/sites-available/default

server:80
root: 站点的root
server:443
同样需要指定

3. 设置邮件服务器

apt-get install nginx apache2-utils fcgiwrap
apt-get install sendmail sendmail-bin
https://major.io/2007/03/27/setting-the-hostname-in-sendmail/

更详细的邮件设置: http://cfig.github.io/2015/09/22/email-notification/

4. 协同github

4.1 github插件

https://gerrit.googlesource.com/plugins/github
在github的pull request之前使用gerrit评审代码
参考步骤 https://github.com/xuanmingyi/blog/blob/master/content/GerritWithGithub.md

4.2 github登陆插件

https://github.com/davido/gerrit-oauth-provider

4.3 github oauth配置

homepage:
http://10.37.116.86:8080
auth callback URL
http://10.37.116.86:8080/oauth

5. LDAP登录

[auth]
        type = LDAP
[httpd]
        listenUrl = http://*:8080/
[ldap]
        server = ldap://XX-ldap.XX.com
        username = me@xx.com
        accountBase = OU=Workers,dc=XX,dc=com
        groupBase = OU=Workers,dc=XX,dc=com

misc

w3m https://g.cf1g.com/ssh_info
curl https://yu@g.cf1g.com/ssh_info -k -u yu
ssh -p 29418 g.cf1g.com
scp -P 29418 g.cf1g.com:hooks/commit-msg .git/hooks/
remember https password: add to .netrc
remember ssh password: .ssh/config

Add gits

ssh -p29418 name@example.com gerrit flush-caches --cache project_list

What if you got “self-signed key issue reported by git”:

workaround: 
git config --global http.sslVerify false

Reference

http://my.oschina.net/zhongl/blog/33017
http://openwares.net/linux/gerrit2\_setup.html

nginx_site_default

server {
    listen 80 default_server;
    listen [::]:80 default_server;

    root /var/www/html;

    index index.html index.htm index.nginx-debian.html;

    server_name _;

    location / {
        try_files $uri $uri/ =404;
    }
}

# HTTPS server
#
server {
    listen 443;
    server_name cf1g.com;

    root /var/www/html;
    index index.html index.htm index.nginx-debian.html;

    ssl on;
    ssl_certificate 2016/1_cf1g.com_bundle.crt;
    ssl_certificate_key 2016/cf1g.rsa;

    ssl_session_timeout 5m;

    ssl_protocols SSLv3 TLSv1;
    ssl_ciphers ALL:!ADH:!EXPORT56:RC4+RSA:+HIGH:+MEDIUM:+LOW:+SSLv3:+EXP;
    ssl_prefer_server_ciphers on;

    location / {
        try_files $uri $uri/ =404;
    }
}