gitweb on nginx

nginx configuration

# Let Nginx handle static files # location ~ ^.*\.git/objects/([0-9a-f]+/[0-9a-f]+|pack/pack-[0-9a-f]+.(pack|idx)) { location ~ ^/[^/]*\.git/objects/([0-9a-f]+/[0-9a-f]+|pack/pack-[0-9a-f]+.(pack|idx)) { auth_basic "strong authentication"; auth_basic_user_file /********/apps/etc/basic.auth.strong.passwords.txt; root /********/GITRepoUbuntu/; } # Pass Git Smart HTTP requests to git-http-backend. Require Auth for everything. # see man git-http-backend for Apache configuration #location ~ ^.*\.git/(HEAD|info/refs|objects/info/.*|git-(upload|receive)-pack)$ { location ~ ^/[^/]*\.git/(HEAD|info/refs|objects/info/.*|git-(upload|receive)-pack)$ { auth_basic "strong authentication"; auth_basic_user_file /********/apps/etc/basic.auth.strong.passwords.txt; client_max_body_size 0; fastcgi_read_timeout 300; fastcgi_buffers 4 64K; include fastcgi_params; fastcgi_pass unix:/var/run/fastcgi.sock; fastcgi_param SCRIPT_FILENAME /usr/lib/git-core/git-http-backend; fastcgi_param GIT_PROJECT_ROOT /********/GITRepoUbuntu; fastcgi_param PATH_INFO $uri; fastcgi_param REMOTE_USER $remote_user; ### Uncomment below to export ALL repositories in GIT_PROJECT_ROOT path. fastcgi_param GIT_HTTP_EXPORT_ALL ""; } location /git/ { auth_basic "strong authentication"; auth_basic_user_file /********/apps/etc/basic.auth.strong.passwords.txt; try_files $uri @gitweb; } location @gitweb { fastcgi_pass unix:/var/run/fastcgi.sock; fastcgi_param SCRIPT_FILENAME /usr/share/gitweb/gitweb.cgi; fastcgi_param PATH_INFO $uri; fastcgi_param GITWEB_CONFIG /etc/gitweb.conf; include fastcgi_params; } # sudo systemctl status nginx fcgiwrap.service fcgiwrap.socket # sudo systemctl enable nginx fcgiwrap.service fcgiwrap.socket # sudo systemctl stop nginx fcgiwrap.service fcgiwrap.socket # sudo systemctl start fcgiwrap.socket fcgiwrap.service nginx

/etc/gitweb.conf

#see man gitweb # path to git projects (.git) $projectroot = "/********/GITRepoUbuntu/"; # directory to use for temp files # $git_temp = "/tmp"; # html text to include at home page # $home_text = "indextext.html"; # file with project list; by default, simply scan the projectroot dir. # $projects_list = "/home/git/projects.list"; @stylesheets = ("gitweb.css"); $javascript = "gitweb.js"; $favicon = "git-favicon.png"; $logo = "git-logo.png"; # git-diff-tree(1) options to use for generated patches @diff_opts = ('-C', '-C'); # enable nicer uris # $feature{pathinfo}{default} = [1]; $site_name = "adrhc's projects"; $home_link = "https://adrhc.go.ro/git/"; $home_link_str = "adrhc's projects"; $mimetypes_file = "/********/apps/etc/nginx/mime.types"; $base_url = "https://adrhc.go.ro/git/"; @git_base_url_list = qw(https://adrhc.go.ro); @extra_breadcrumbs = ( [ "adrhc's blog" => "https://adrhc.go.ro/" ] );

/etc/systemd/system/fcgiwrap.socket

[Unit] Description=fcgiwrap Socket [Socket] SocketMode=0660 SocketUser**** SocketGroup********* ListenStream=/var/run/fastcgi.sock [Install] WantedBy=sockets.target

/etc/systemd/system/fcgiwrap.service

[Unit] Description=Simple CGI Server After=nss-user-lookup.target [Service] # https://apuntesderootblog.wordpress.com/2015/06/01/how-to-run-gitweb-and-git-http-backend-with-nginx-in-fedora/ # sudo apt-get install fcgiwrap # systemctl daemon-reload # sudo systemctl enable fcgiwrap.socket fcgiwrap.service ExecStartPre=/bin/mkdir -p /var/cache/cgit ExecStartPre=/bin/chown ************ /var/cache/cgit #ExecStartPre=/bin/rm -rf /var/cache/cgit/* ExecStart=/usr/sbin/fcgiwrap User**** Group********* [Install] Also=fcgiwrap.socket

example bare repository config

cat /********/GITRepoUbuntu/test/git/config [core] repositoryformatversion = 0 filemode = false bare = true sharedrepository = 1 [receive] denyNonFastforwards = true [alias] st = status gr = log --full-history --all --graph --color --date-order --pretty=format:"%x1b[31m%h%x09%x1b[32m%d%x1b[0m%x20%s" ci = commit cim = commit -m ck = checkout ckm = checkout master ckd = checkout dev rs = reset mgnf = merge --no-ff mg = merge pom = push origin master pod = push origin development gom = pull origin master god = pull origin development [gitg] mainline = refs/heads/master # ERROR git clone https://adrhc.go.ro/exifweb.git edit some files then commit ... git push origin master Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (3/3), done. Writing objects: 100% (3/3), 303 bytes | 0 bytes/s, done. Total 3 (delta 2), reused 0 (delta 0) remote: error: unable to create temporary file: Operation not permitted remote: fatal: failed to write object error: unpack failed: unpack-objects abnormal exit To https://adrhc.go.ro/exifweb.git ! [remote rejected] master -> master (unpacker error) error: failed to push some refs to 'https://adrhc.go.ro/exifweb.git' # SOLUTION Make sure the user and group (and SocketMode) set for fcgiwrap OS service are appropriate for the git repository (when using http/https push).

Spring security

HTML translated to java config
see also Java Configuration
see also http://www.springframework.org/schema/security/spring-security.xsd

<http security="none" pattern="/resources/**"/>
<http pattern="/api1/**" create-session="stateless">
	<intercept-url pattern="/**" access="authenticated"/>
	<http-basic />
</http>
<http pattern="/api2/**" create-session="never">
	<intercept-url pattern="/api2/api21/**" access="hasRole('ROLE_ADMIN')"/>
	<intercept-url pattern="/api2/**" access="hasRole('ROLE_USER')"/>
	<http-basic />
</http>
<http pattern="/api3/**">
	<intercept-url pattern="/api3/api31/**" access="hasRole('ROLE_ADMIN')"/>
	<intercept-url pattern="/api3/api32/**" access="hasRole('ROLE_USER')"/>
	<intercept-url pattern="/**" access="authenticated"/>
	<http-basic />
</http>
<http>
	<intercept-url pattern="/logout" access="permitAll"/>
	<intercept-url pattern="/login" access="permitAll"/>
	<intercept-url pattern="/**" access="hasRole('ROLE_USER')"/>
	...
	<form-login login-page="/services/session" login-processing-url="/login"
				password-parameter="password" username-parameter="username"
				logout-success-url="/services/session" ... />
	<http-basic />
	<logout invalidate-session="true"/>
</http>
@Configuration
@EnableWebSecurity
public class WebSecurityConfig {
    @Autowired
    private AuthenticationManager am;

    /**
     * @param auth
     * @throws Exception
     */
    @Autowired
    public void configureGlobal(final AuthenticationManagerBuilder auth) throws Exception {
        auth.parentAuthenticationManager(this.am);
    }
}
@Configuration
@Order(1)
public class Api1Authentication extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(final HttpSecurity httpSecurity) throws Exception {
		httpSecurity.antMatcher("/api1/**")
					.authorizeRequests().anyRequest().authenticated()
					.and()
					.httpBasic()
					.and()
					.sessionManagement()
					.sessionCreationPolicy(SessionCreationPolicy.STATELESS);    
	}
}
@Configuration
@Order(2)
public class Api2Authentication extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(final HttpSecurity httpSecurity) throws Exception {
		httpSecurity.antMatcher("/api2/**")
					.authorizeRequests()
					.antMatchers("/api2/api21/**").hasRole("ADMIN")
					.antMatchers("/api2/**").hasRole("USER")
					.and()
					.httpBasic()
					.and()
					.sessionManagement()
					.sessionCreationPolicy(SessionCreationPolicy.NEVER);    
	}
}
@Configuration
@Order(3)
public class Api3Authentication extends WebSecurityConfigurerAdapter {
	@Override
	protected void configure(final HttpSecurity httpSecurity) throws Exception {
		httpSecurity.antMatcher("/api3/**")
					.authorizeRequests()
					.antMatchers("/api3/api31/**").hasRole("ADMIN")
					.antMatchers("/api3/api32/**").hasRole("USER")
					.anyRequest().authenticated()
					.and()
					.httpBasic();    
	}
}
@Configuration
public class OtherAuthentication extends WebSecurityConfigurerAdapter {
    @Override
    public void configure(final WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

    @Override
    protected void configure(final HttpSecurity httpSecurity) throws Exception {
        httpSecurity.authorizeRequests()
                    .anyRequest().authenticated()
                    .and()
                    .formLogin()
                    .loginPage("/services/session")
                    .loginProcessingUrl("/login")
                    .usernameParameter("username")
                    .passwordParameter("password")
                    .defaultSuccessUrl("/services/session")
                    .failureHandler(new DdcAuthenticationFailureHandler())
                    .permitAll()
                    .and()
                    .httpBasic()
                    .and()
                    .logout()
                    .logoutSuccessUrl("/services/session")
                    .invalidateHttpSession(true);
    }
}
Q1: why should I use antMatcher("/api2/**") while anyway the subsequent antMatchers(...) cover the entiy /api2/** paths?
A1: because antMatcher has the purpose of mapping the  security configuration while antMatchers accompanies authorizeRequests() in order to specify request access conditions (e.g. roles). antMatchers could accompany also requiresChannel() in order to specify the protocol (http, https, any). If not using antMatcher that would be like  security configuration wouldn't use the pattern attribute (equivalent to using /**).

OtherAuthentication allows the use of form and basic authentication (using the order of declaration). So when not authenticated user access /services/session (using no Authorization header) he would get back a response (e.g. json containing a CSRF token :D). When the user tries to POST /services/session using the received CSRF token he will then be authenticated using basic authentication when he use Authorization header or form authentication otherwise (suppose he uses a valid token otherwise spring will consider a CSRF attack). When one tries to access /some-not-resources-and-not-api123-path with the header Authorization filled with a valid user/password than the basic authentication will be enforced and the user will get the result; if user/password is wrong he will get http code 401. 

/api2/** has SessionCreationPolicy.NEVER which means it won't create a session (when using basic authentication) but it might use one when the user already created one like when authenticated with form-authentication.

/api1/** has SessionCreationPolicy.STATELESS which means it will not create a session but also it will invalidate it if found so it does not live well with OtherAuthentication which creates (in order to use) a session. This means that after a form authentication the user will be disconnected after trying to access /api1/**.

Linux various commands

# show only first line found:
grep "search this" nohup.out | sed -n '1p'
# show only last line found:
grep "search this" nohup.out | sed -n '$p'

# copy to current path the file /home/gigi/systemctl-services.txt 
# from adrhc.go.ro (remote ssh server) using custom ssh port 27
scp -P 27 gigi@adrhc.go.ro:/home/gigi/systemctl-services.txt .

Ubuntu and Oracle

# see also https://wiki.centos.org/HowTos/Oracle12onCentos7
# see also https://adrhc.go.ro/wordpress/centos-and-oracle/

# Follow this (works with Ubuntu 16.04 too):
# http://www.techienote.com/install-oracle-12c-on-ubuntu/

# systemd oracle.service (working when only one db is automatically started with /etc/oratab)
[Unit]
Description=Oracle 12c
After=local-fs.target
Wants=local-fs.target

[Service]
Type=forking

User=oracle
Group=oinstall

RuntimeDirectory=oracle
PIDFile=/run/oracle/oracle.pid

Restart=on-failure
RestartSec=3

TimeoutSec=0

ExecStart=/u01/app/oracle/product/12.1.0/dbhome_1/bin/dbstart /u01/app/oracle/product/12.1.0/dbhome_1
ExecStop=/u01/app/oracle/product/12.1.0/dbhome_1/bin/dbshut /u01/app/oracle/product/12.1.0/dbhome_1

[Install]
WantedBy=multi-user.target

# modify dbstart and dbshut in order to create /run/oracle/oracle.pid needed by oracle.service
# /u01/app/oracle/product/12.1.0/dbhome_1/bin/dbstart
startinst() {
...
      if [ $? -eq 0 ] ; then
        echo "" 
		OS_PID=$(sqlplus -S / AS SYSDBA <<EOF
select SPID from v\$process where PNAME = 'PMON';
EOF
)
		OS_PID=$(echo "$OS_PID" | /bin/grep -P "\d+")
        echo "$0: ${INST} \"${ORACLE_SID}\" warm started (PID $OS_PID)." 
		if [ -d /run/oracle ]; then
			echo "$OS_PID" > /run/oracle/oracle.pid
			echo "created /run/oracle/oracle.pid"
		fi
      else
        $LOGMSG "" 
        $LOGMSG "Error: ${INST} \"${ORACLE_SID}\" NOT started." 
      fi
# /u01/app/oracle/product/12.1.0/dbhome_1/bin/dbshut
  if test $? -eq 0 ; then
	if [ -f /run/oracle/oracle.pid ]; then
		# see /u01/app/oracle/product/12.1.0/dbhome_1/bin/dbstart
		rm -fv /run/oracle/oracle.pid
	fi
    echo "${INST} \"${ORACLE_SID}\" shut down."
  else
    echo "${INST} \"${ORACLE_SID}\" not shut down."
  fi

Docker

# pull and run an image
docker run hello-world
docker run -itP centos cat /etc/redhat-release
# lists all the images on your local system
docker images --help
docker images
# show all containers on the system
docker ps --help
docker ps -a
docker ps --no-trunc -a
# log into the Docker Hub
docker login --username=yourhubusername
# removing containers
docker ps -a
docker rm --help
docker rm 6075298d5896
# modify an image
docker run -itP -v "$HOME/KIT":/adrhc/KIT -v /home/adrk/certs/:/adrhc/certs centos /bin/bash
cd root
yum -y update
yum install -y wget
wget https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm
yum localinstall -y epel-release-latest-7.noarch.rpm
yum -y update
yum install -y nano mlocate zip unzip iftop htop net-tools openssh-clients openssh-server which sysvinit-tools psmisc less man-db openssl davfs2 fuse
# configure sshd
sed -i s/"#Port 22"/"Port 322"/ /etc/ssh/sshd_config
# if you want to change the port on a SELinux system, you have to tell SELinux about this change:
semanage port -a -t ssh_port_t -p tcp 322
# solving ERROR: Could not load host key: /etc/ssh/ssh_host_rsa_key
/usr/bin/ssh-keygen -A
/usr/sbin/sshd
netstat -tulpn
CTRL+D
# committing d513e8dff620 container to a new named adrhc/centos7:v2 image:
docker commit -m "CentOS + epel" -a "adrhc" d513e8dff620 adrhc/centos7:v2
# or commit using the container's name (gloomy_goldstine) to a new named adrhc/centos7:v2 image:
docker commit -m "CentOS + epel" -a "adrhc" gloomy_goldstine adrhc/centos7:v2
# or commit last created container to a new named adrhc/centos7:v2 image:
docker commit -m "CentOS + epel" -a "adrhc" `docker ps -lq` adrhc/centos7:v2
# push an image to Docker Hub (see it at https://cloud.docker.com/_/repository/list)
docker push adrhc/centos7
# run the above commited image:
docker run -itP -v "$HOME/KIT":/adrhc/KIT -v /home/adrk/certs/:/adrhc/certs adrhc/centos7:v2 /bin/bash -> will create the container 3a63cfee66f4
# renaming 3a63cfee66f4 container created above
docker ps -a | grep 3a63cfee66f4
docker rename 3a63cfee66f4 my_centos7
# or rename last created container:
docker rename `docker ps -lq` my_centos7
# re-running the container 3a63cfee66f4
docker start 3a63cfee66f4
docker start my_centos7
# connecting to/bringing to front the running container
docker attach 3a63cfee66f4
docker attach my_centos7
# detach (see https://groups.google.com/forum/#!msg/docker-user/nWXAnyLP9-M/kbv-FZpF4rUJ)
docker run -i -t → can be detached with ^P^Q and reattached with docker attach
docker run -i → cannot be detached with ^P^Q; will disrupt stdin
docker run → cannot be detached with ^P^Q; can SIGKILL client; can reattach with docker attach
# stopping a running container
docker stop my_centos7
# get the IP address of the running my_centos7 container
docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my_centos7
# remove container
docker rm 3a63cfee66f4
# or by name
docker rm my_centos7
# remove image
docker images; docker ps -a
docker rmi 143d6907480f
docker rmi -f 143d6907480f -> removes related containers too
# connect using ssh to the container named my_centos7
# make sure the container exposes desired ports (https://docs.docker.com/engine/reference/commandline/run/)
ssh -p 322 root@`docker inspect --format='{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' my_centos7`

Systemd and systemctl

# see https://www.freedesktop.org/wiki/Software/systemd/TipsAndTricks/

systemctl                           -> shows all active units
systemctl list-units --type=service -> shows all active services (--all to see loaded but inactive services too)
systemctl list-units --type=swap	-> shows swap unit configurations

# show cgroup tree
systemd-cgls

# services started by multi-user.target
systemctl show -p "Wants" multi-user.target | less

###################
# svnserve.service:
#
# sudo chown ************ bin/svnserve.service && sudo chmod 664 bin/svnserve.service && cp -v bin/svnserve.service /etc/systemd/system/ && sudo chown root: /etc/systemd/system/svnserve.service && sudo chmod 664 /etc/systemd/system/svnserve.service && sudo systemctl daemon-reload
# or
# sudo chown ************ bin/svnserve.service
# sudo chmod 664 bin/svnserve.service
# cp -v bin/svnserve.service /etc/systemd/system/
# sudo chown root: /etc/systemd/system/svnserve.service
# sudo chmod 664 /etc/systemd/system/svnserve.service
# sudo systemctl daemon-reload

# sudo systemctl status svnserve
# sudo systemctl enable svnserve
# sudo systemctl start svnserve
# journalctl -xe
# journalctl -xf

[Unit]
Description=Server for the 'svn' repository access method

# see https://www.freedesktop.org/software/systemd/man/systemd.unit.html#
# see https://www.freedesktop.org/software/systemd/man/systemd.special.html#
After=local-fs.target
Wants=local-fs.target

[Service]
Type=forking

User****
Group*********

RuntimeDirectory=svnserve
RuntimeDirectoryMode=750

PIDFile=/run/svnserve/svnserve.pid

# RuntimeDirectory is doing this:
# User****
# Group*********
# PIDFile=/run/svnserve/svnserve.pid
# PermissionsStartOnly=true
# ExecStartPre=/bin/mkdir /run/svnserve
# ExecStartPre=/bin/chown ************ /run/svnserve

KillMode=process
Restart=on-failure
RestartSec=3

# A shorthand for configuring both TimeoutStartSec= and TimeoutStopSec= to the specified value.
TimeoutSec=5

# -r root, --root=root
#	Sets  the  virtual  root for repositories served by svnserve.  
#	The pathname in URLs provided by the client will be interpreted 
#	relative to this root, and will not be allowed to escape this root.
ExecStart=/usr/bin/svnserve -d -r /mnt/1TB/DataWin_to_sync/SVNRepoLinux --log-file /********/apps/log/svnserve.log --pid-file /run/svnserve/svnserve.pid

[Install]
WantedBy=multi-user.target

######################
# couchpotato.service:
#
[Unit]
Description=CouchPotato
After=local-fs.target
Wants=local-fs.target

[Service]
Type=simple
User****
Group*********
RuntimeDirectory=couchpotato
RuntimeDirectoryMode=750
PIDFile=/run/couchpotato/couchpotato.pid
# KillMode=process
# Restart=on-failure
# RestartSec=3
TimeoutStartSec=60
TimeoutStopSec=15

# couchpotato.service: Supervising process 22342 which is not our child. We'll most likely not notice when it exits
#
# ExecStart=/usr/bin/python /********/apps/opt/couchpotato/CouchPotato.py --config_file /********/apps/etc/couchpotato.conf --daemon --data_dir /********/apps/opt/couchpotato_data --pid_file /run/couchpotato/couchpotato.pid

ExecStart=/usr/bin/python /********/apps/opt/couchpotato/CouchPotato.py --config_file /********/apps/etc/couchpotato.conf --data_dir /********/apps/opt/couchpotato_data --quiet

[Install]
WantedBy=multi-user.target

###################
# anytermd.service:
#
[Unit]
Description=A Terminal Anywhere
After=local-fs.target
Wants=local-fs.target

[Service]
Type=forking
PIDFile=/run/anytermd.pid

KillMode=process
Restart=on-failure
RestartSec=3
TimeoutSec=5

# anytermd.service: Main process exited, code=exited, status=1/FAILURE
#
# ExecStart=/********/apps/bin/anytermd --command "/bin/login -p adr" --port 23456 --user root --local-only
# ExecStart=/********/apps/bin/anytermd --command "/bin/login -p adr" --port 23456 --user root --foreground --local-only
SuccessExitStatus=1
ExecStart=/********/apps/bin/anytermd --command "/bin/login -p adr" --port 23456 --user root --local-only

[Install]
WantedBy=multi-user.target

################
# tomcat.service
#
[Unit]
Description=Apache Tomcat
After=local-fs.target network.target
Wants=local-fs.target

[Service]
Type=forking
WorkingDirectory=~
RuntimeDirectory=tomcat
RuntimeDirectoryMode=750
PIDFile=/run/tomcat/tomcat.pid
User****
Group*********
Environment=CATALINA_HOME=/********/apps/opt/apache-tomcat-7.0.64
Environment=CATALINA_PID=/run/tomcat/tomcat.pid
PermissionsStartOnly=true
ExecStartPre=/bin/rm -vf /********/apps/opt/apache-tomcat-7.0.64/logs/*
ExecStartPre=/bin/rm -vf /********/exifweb*.log

## KillMode=process
# Restart=on-failure
# RestartSec=3
TimeoutStartSec=60
TimeoutStopSec=15

# ExecStart=/bin/sh -c 'CATALINA_PID=/run/tomcat.pid /********/apps/opt/apache-tomcat-7.0.64/bin/startup.sh'
ExecStart=/********/apps/opt/apache-tomcat-7.0.64/bin/startup.sh
ExecStop=/********/apps/opt/apache-tomcat-7.0.64/bin/shutdown.sh

[Install]
WantedBy=multi-user.target