<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/xsl" href="../assets/xml/rss.xsl" media="all"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Knowledge Base (Posts about selfhosting)</title><link>https://bgstack15.ddns.net/blog/</link><description></description><atom:link href="https://bgstack15.ddns.net/blog/categories/selfhosting.xml" rel="self" type="application/rss+xml"></atom:link><language>en</language><copyright>Contents © 2025 &lt;a href="mailto:bgstack15@gmail.com"&gt;bgstack15&lt;/a&gt; 
&lt;a rel="license" href="https://www.gnu.org/licenses/gpl-3.0.html"&gt;
&lt;img alt="GNU General Public License v3.0"
style="border-width:0; margin-bottom:12px;"
src="https://bgstack15.ddns.net/.images/gplv3-127x51.png"&gt;&lt;/a&gt;</copyright><lastBuildDate>Tue, 09 Dec 2025 14:15:37 GMT</lastBuildDate><generator>Nikola (getnikola.com)</generator><docs>http://blogs.law.harvard.edu/tech/rss</docs><item><title>Trying owntracks to track my mobile devices</title><link>https://bgstack15.ddns.net/blog/posts/2025/11/11/trying-owntracks-to-track-my-mobile-devices/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;I was reading some discussion on &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/news.ycombinator.com/"&gt;Hacker News&lt;/a&gt; and the fine folks there mentioned &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/Freika/dawarich"&gt;Dawarich&lt;/a&gt;, a self-hostable server for managing your location data. I got interested in this sort of thing. I've never really used stuff like this before for myself, even from the big names. I use Google Maps for navigation, but not for showing myself my location history. I'm sure the setting for "do not record my location" merely turns off my ability to look it up; I'm sure Google still knows exactly where my mobile device has been (that is not the same as where I have been) across all of time.&lt;/p&gt;
&lt;p&gt;But &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/f-droid.org/"&gt;F-Droid&lt;/a&gt; didn't have the Dawarich app, but it had the &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/f-droid.org/en/packages/org.owntracks.android/"&gt;app&lt;/a&gt; for &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/owntracks.org/"&gt;owntracks&lt;/a&gt;, a similar tool.&lt;/p&gt;
&lt;h2&gt;Stackrpms installation of owntracks&lt;/h2&gt;
&lt;p&gt;This application is for tracking my location history on my own infrastructure.&lt;/p&gt;
&lt;h2&gt;Goals&lt;/h2&gt;
&lt;p&gt;I want to be able to view my location history. In the past, I used Google Maps location history to find where I had stayed on a particular vacation. I want to be able to do this sort of auditing without depending on external vendors.&lt;/p&gt;
&lt;h2&gt;Setup&lt;/h2&gt;
&lt;p&gt;This application is installed in docker on server4.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;sudo useradd owntracks
sudo usermod -a -G docker owntracks
sudo su - owntracks
mkdir -p compose ; cd compose
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I established file docker-compose.yml and config.js. I just picked random ports available, including server4:8083 for recorder, and server4:8085 for frontend.&lt;/p&gt;
&lt;p&gt;On server3, set up custom apache httpd config &lt;code&gt;owntracks.cnf&lt;/code&gt; which is an adaptation of [Reference #5][5]. Adapt local_mirror.conf to include this for VirtualHosts 443 (internal https) and 444 (external https).&lt;/p&gt;
&lt;p&gt;Establish new password repository. Use password scheme 3j.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;as&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;root&lt;/span&gt;&lt;span class="nv"&gt;@server3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;htpasswd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owntracks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;device5&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;htpasswd&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;owntracks&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;device4&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Added a port in the firewall on server4.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;sudo firewall-cmd --add-port=8083/tcp
sudo firewall-cmd --add-port=8085/tcp
sudo firewall-cmd --add-port=1883/tcp
sudo firewall-cmd --add-port=8883/tcp
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I established the container &lt;code&gt;mosquitto&lt;/code&gt;, which uses its own TLS cert. The &lt;code&gt;openssl req&lt;/code&gt; needed to be run on a newer system where parameter &lt;code&gt;-addext&lt;/code&gt; can be used. I ran the &lt;code&gt;ipa cert-request&lt;/code&gt; from server4 which owns the service we add here.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;openssl genpkey -algorithm RSA -out https-server4.ipa.internal.com.key
openssl req -new -key https-server4.ipa.internal.com.key -subj "/O=IPA.INTERNAL.COM/CN=server4.ipa.internal.com" -addext "subjectAltName = DNS:server4.ipa.internal.com,DNS:www.example.com" -out https-server4.ipa.internal.com.csr
ipa service-add --force HTTP/server4.ipa.internal.com
ipa cert-request --principal=HTTP/server4.ipa.internal.com https-server4.ipa.internal.com.csr --certificate-out=https-server4.ipa.internal.com.pem
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I configured the main router to forward port 8883/tcp to server4:8883. There might be a way to use an apache httpd reverse proxy for websockets to mqtt, but I have not investigated that.&lt;/p&gt;
&lt;p&gt;To establish the mosquitto password database, use &lt;code&gt;-c&lt;/code&gt; in the command, inside the container.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;mosquitto_passwd -c /mosquitto/config/password_file recorder
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The rest of the commands will omit &lt;code&gt;-c&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The mosquitto config is in file &lt;code&gt;mosquitto-conf/mosquitto.conf&lt;/code&gt;, and uses TLS.&lt;/p&gt;
&lt;h3&gt;Establishing useful contact info with &lt;em&gt;cards&lt;/em&gt;&lt;/h3&gt;
&lt;p&gt;I want to be able to see pretty names/faces for "friends". &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/owntracks.org/booklet/features/card/"&gt;https://owntracks.org/booklet/features/card/&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;I Used &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/owntracks/recorder/raw/refs/heads/master/contrib/faces/image2card.sh"&gt;https://github.com/owntracks/recorder/raw/refs/heads/master/contrib/faces/image2card.sh&lt;/a&gt; from &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/owntracks/recorder/blob/master/contrib/faces/image2card.sh"&gt;https://github.com/owntracks/recorder/blob/master/contrib/faces/image2card.sh&lt;/a&gt; to do this:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;sh image2card.sh user1.jpg "user1" "na" &amp;gt; device5-device5.json
sh image2card.sh user2.png "user2" "nn" &amp;gt; device4-device4.json
sh image2card.sh user3.png "user3" "eo" &amp;gt; device2-device2.json
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I prepared these so they are accessible for container &lt;code&gt;mosquitto&lt;/code&gt; in &lt;code&gt;/mosquitto/config/cards/&lt;/code&gt;, and then entered the container and ran these commands.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;compose&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;exec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mosquitto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;mosquitto_pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'mqtt://recorder:KEEPASS@localhost:1883/owntracks/device5/device5/info'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;f&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;mosquitto&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;config&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;device5&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;device5&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;q&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;To remove/delete a card:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="n"&gt;mosquitto_pub&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;L&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'mqtt://recorder:KEEPASS@localhost:1883/owntracks/device5/device5/info'&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;d&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Associated files&lt;/h2&gt;
&lt;p&gt;On server &lt;code&gt;server4&lt;/code&gt;.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/home/owntracks/compose&lt;ul&gt;
&lt;li&gt;config.js, taken from official example &lt;a href="https://github.com/owntracks/frontend/blob/main/public/config/config.example.js"&gt;https://github.com/owntracks/frontend/blob/main/public/config/config.example.js&lt;/a&gt; for frontend.&lt;/li&gt;
&lt;li&gt;docker-compose.yml, very simple combination of official compose example files for recorder (backend) and frontend.&lt;/li&gt;
&lt;li&gt;mosquitto-conf/password_file&lt;/li&gt;
&lt;li&gt;mosquitto-conf/mosquitto.conf&lt;/li&gt;
&lt;li&gt;mosquitto-conf/https-server4.ipa.internal.com.key&lt;/li&gt;
&lt;li&gt;mosquitto-conf/https-server4.ipa.internal.com.pem&lt;/li&gt;
&lt;li&gt;mosquitto-conf/ca-ipa.internal.com.pem&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;code&gt;mosquitto-conf/cards&lt;/code&gt; directory of custom .json files for "cards" that describe the various devices, and the script that loads them&lt;/p&gt;
&lt;h2&gt;!/bin/sh&lt;/h2&gt;
&lt;p&gt;cd "${1}"
for word in *.json ; do echo "${word%%.json}" | while IFS='-' read a b ; do mosquitto_pub -L "mqtt://recorder:KEEPASS@localhost:1883/owntracks/${a}/${b}/info" -f "${word}" -r -q 2 -d ; done ; done&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On server &lt;code&gt;server3&lt;/code&gt;, the main web server.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;/etc/httpd/conf.d/owntracks.cnf&lt;/li&gt;
&lt;li&gt;/etc/httpd/conf.d/local_mirror.conf includes owntracks.cnf in virtualhosts 443 and 444.&lt;/li&gt;
&lt;li&gt;/etc/httpd/.owntracks (or similar) for the credential.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Associated urls&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://server4.ipa.internal.com:8083"&gt;http://server4.ipa.internal.com:8083&lt;/a&gt; recorder. The main url for the apps includes virtual path &lt;code&gt;/pub&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;&lt;a href="http://server4.ipa.internal.com:8085"&gt;http://server4.ipa.internal.com:8085&lt;/a&gt; frontend&lt;/li&gt;
&lt;li&gt;&lt;a href="https://www.example.com/owntracks"&gt;https://www.example.com/owntracks&lt;/a&gt; reverse proxy to recorder.&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Operations&lt;/h2&gt;
&lt;h3&gt;Restarting the containers&lt;/h3&gt;
&lt;p&gt;Connect to owntracks@server4.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker-compose pull ; docker-compose down ; docker-compose up -d
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Adding a new device&lt;/h3&gt;
&lt;h4&gt;Adding a device for MQTT auth&lt;/h4&gt;
&lt;p&gt;Connect to the mosquitto container and then modify the existing password file. The username will probably be the device name.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;compose&lt;/span&gt; &lt;span class="k"&gt;exec&lt;/span&gt; &lt;span class="nv"&gt;mosquitto&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;bin&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;sh&lt;/span&gt;
&lt;span class="nv"&gt;mosquitto_passwd&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;mosquitto&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;password_file&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;username&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;password&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I am not sure if container &lt;code&gt;mosquitto&lt;/code&gt; needs to be restarted to take effect.&lt;/p&gt;
&lt;p&gt;Configure the client settings Connection.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;Mode=MQTT
Host=www.example.com
Port=8883
Client ID=&amp;lt;device name&amp;gt;
Use Websockets=True
Device ID=&amp;lt;device name&amp;gt;
Tracker ID=?????
Username=&amp;lt;from password_file&amp;gt;
Password=&amp;lt;from password_file&amp;gt;
TLS=True
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Make sure the android device trusts the CA cert, which is available at &lt;a href="https://server3/internal/certs/ca-ipa.internal.com.crt"&gt;https://server3/internal/certs/ca-ipa.internal.com.crt&lt;/a&gt;&lt;/p&gt;
&lt;h4&gt;Adding a device for http auth&lt;/h4&gt;
&lt;p&gt;&lt;strong&gt;WARNING&lt;/strong&gt; I think this might work, but it also might not work anymore now with MQTT usage.&lt;/p&gt;
&lt;p&gt;I have decided to use a separate http credential for each device. Visit server3 and set up a new credential in the password file. This example shows adding &lt;strong&gt;device4&lt;/strong&gt;.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;sudo htpasswd -c /etc/httpd/.owntracks device4
&amp;lt;enter a password, probably "KEEPASS"&amp;gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It is not necessary to reload the web server. Then configure OwnTracks on the new device to use this http endpoint.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;www&lt;/span&gt;.&lt;span class="nv"&gt;example&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;owntracks&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;pub&lt;/span&gt;
&lt;span class="nv"&gt;Device&lt;/span&gt; &lt;span class="nv"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;device4&lt;/span&gt;
&lt;span class="nv"&gt;Tracker&lt;/span&gt; &lt;span class="nv"&gt;ID&lt;/span&gt;&lt;span class="o"&gt;=&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;anything&lt;/span&gt; &lt;span class="nv"&gt;will&lt;/span&gt; &lt;span class="k"&gt;do&lt;/span&gt; &lt;span class="nv"&gt;fine&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="nv"&gt;Username&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;device4&lt;/span&gt;
&lt;span class="nv"&gt;Password&lt;/span&gt;&lt;span class="o"&gt;=&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;same&lt;/span&gt; &lt;span class="nv"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;htpasswd&lt;/span&gt; &lt;span class="nv"&gt;command&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Removing data about an old user/device combo.&lt;/h3&gt;
&lt;p&gt;To remove user "user" device "device5", run this command:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;# on server4
sudo rm -rf /home/owntracks/compose/owntracks-recorder/store/last/user/device5
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I am not sure if this removes info in the frontend for this user+device.&lt;/p&gt;
&lt;h3&gt;Viewing server app logs&lt;/h3&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker-compose logs -f otrecorder mosquitto
&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Viewing location history&lt;/h3&gt;
&lt;p&gt;Visit &lt;a href="http://server4:8085/"&gt;http://server4:8085/&lt;/a&gt; which is container &lt;code&gt;frontend&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Re-adding the cards&lt;/h3&gt;
&lt;p&gt;A card is the pretty info about a device, such as user name and picture. These are hand-curated with a useful script (search &lt;strong&gt;image2card.sh&lt;/strong&gt; in the install section), and after a container restart, you need to reload these.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nv"&gt;docker&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;compose&lt;/span&gt; &lt;span class="k"&gt;exec&lt;/span&gt; &lt;span class="nv"&gt;mosquitto&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;mosquitto&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;cards&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;import&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;cards&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;mosquitto&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;config&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;cards&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/bhdouglass.com/blog/self-hosted-device-tracking-with-owntracks/"&gt;Self-Hosted device tracking with OwnTracks | Brian Douglass&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/hub.docker.com/r/owntracks/recorder"&gt;owntracks/recorder - Docker Image | Docker Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/owntracks/frontend"&gt;owntracks/frontend: 🌍 Web interface for OwnTracks built with Vue.js&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/hub.docker.com/r/owntracks/frontend"&gt;owntracks/frontend - Docker Image | Docker Hub&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/l33tn00b/owntracks/blob/main/reverse-proxy.conf"&gt;owntracks/reverse-proxy.conf at main · l33tn00b/owntracks&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/stackoverflow.com/questions/77953196/how-to-configure-two-mosquitto-listeners-with-different-protocols"&gt;mqtt - How to configure two Mosquitto listeners with different protocols? - Stack Overflow&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/bgstack15.ddns.net/blog/posts/2023/10/02/latest-way-to-get-certificate-in-freeipa/"&gt;Latest way to get certificate in FreeIPA | Knowledge Base&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/oransblog.com/owntracks/"&gt;How to setup selfhosted owntracks server&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/owntracks.org/booklet/features/card/"&gt;Card - OwnTracks Booklet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/owntracks.org/booklet/features/friends/"&gt;Friends - OwnTracks Booklet&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/duckduckgo.com/?t=ffab&amp;amp;q=mosquitto_pub+delete+topic&amp;amp;ia=web"&gt;mosquitto_pub delete topic at DuckDuckGo&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;Alternate reading&lt;/h3&gt;
&lt;p&gt;In case I want to experiment with using httpd to reverse-proxy MQTT or websockets.&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/www.rushworth.us/lisa/?p=358"&gt;https://www.rushworth.us/lisa/?p=358&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/superuser.com/questions/1220259/mosquitto-apache"&gt;proxy - Mosquitto + Apache - Super User&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="nt"&gt;&amp;lt;VirtualHost&lt;/span&gt; &lt;span class="err"&gt;*:1883&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        ProxyRequests Off
        ProxyPreserveHost On
        ProxyPass /mqtt ws://$Broker-IP:$Broker-Port
        ProxyPassReverse /mqtt ws://$Broker-IP:$Broker-Port
&lt;span class="nt"&gt;&amp;lt;/VirtualHost&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/karloluiten.nl/n8n-apache2-reversed-proxy-fix-websockets/"&gt;n8n apache2 reverse proxy fix websockets – 🔐 Karlo Luiten&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IfModule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mod_ssl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;c&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;VirtualHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;443&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;SSLEngine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;off&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ServerAdmin&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;webmaster&lt;/span&gt;&lt;span class="nv"&gt;@karloluiten&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ServerName&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n8n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;karloluiten&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;DocumentRoot&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;"/var/www/html/"&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ErrorLog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;"${APACHE_LOG_DIR}/error_n8n.servar_nl.log"&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;CustomLog&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;${&lt;/span&gt;&lt;span class="n"&gt;APACHE_LOG_DIR&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;access_n8n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;servar_nl&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;log&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;combined&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RequestHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Forwarded&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Proto&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;https&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RemoteIPHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Forwarded&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;For&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RequestHeader&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;Forwarded&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;Host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ss"&gt;"%{SERVER_NAME}e"&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ProxyPreserveHost&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;Off&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ProxyPass&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.0.40.54&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5678&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ProxyPassReverse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.0.40.54&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5678&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RewriteEngine&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;On&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RewriteCond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Upgrade&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NC&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RewriteRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nl"&gt;ws&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.0.40.54&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5678&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P,L&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RewriteCond&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;%&lt;/span&gt;&lt;span class="err"&gt;{&lt;/span&gt;&lt;span class="nl"&gt;HTTP&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;Upgrade&lt;/span&gt;&lt;span class="err"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="n"&gt;websocket&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NC&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;RewriteRule&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="p"&gt;(.&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="nl"&gt;http&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="mf"&gt;10.0.40.54&lt;/span&gt;&lt;span class="err"&gt;:&lt;/span&gt;&lt;span class="mi"&gt;5678&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="err"&gt;$&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;P,L&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;ProxyPassReverse&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="nl"&gt;https&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="n"&gt;n8n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;karloluiten&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;SSLCertificateFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;letsencrypt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;live&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;n8n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;karloluiten&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;fullchain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;SSLCertificateKeyFile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;letsencrypt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;live&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;n8n&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;karloluiten&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;nl&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;privkey&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pem&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;Include&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;letsencrypt&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;options&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;ssl&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;apache&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;conf&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;VirtualHost&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="n"&gt;IfModule&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Obviously fill in your own details/domains/ip.&lt;/p&gt;
&lt;p&gt;Also for env vars:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;N8N_BASIC_AUTH_ACTIVE=true
N8N_BASIC_AUTH_USER=admin
N8N_BASIC_AUTH_PASSWORD=xxx
N8N_SECURE_COOKIE=false
WEBHOOK_URL=https://n8n.karloluiten.nl/
N8N_PROXY_HOPS=1
&lt;/pre&gt;&lt;/div&gt;

&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/www.rushworth.us/lisa/?p=8762"&gt;Reverse Proxying WebSockets through mod_proxy — HTTP Failback – Lisa's Home Page&lt;/a&gt;&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;I’ve been successfully reverse proxying MQTT over WebSockets via Apache HTTPD for quite some time now. The last few weeks, my phone isn’t able to connect. There’s no good rational presented (and manually clicking the “send data” button on my client successfully connects). It was time to upgrade the server anyway. Once I got the latest Linux distro on the server, I couldn’t connect at all to my MQTT server. The error log showed AH00898: Error reading from remote server returned by /mqtt&lt;/p&gt;
&lt;p&gt;Evidently, httpd 2.4.47 added functionality to upgrade and tunnel in accordance with RFC 7230. And that doesn’t work at all in my scenario. Haven’t dug in to the why of it yet, but adding &lt;code&gt;ProxyWebsocketFallbackToProxyHttp Off&lt;/code&gt; to the reverse proxy config allowed me to successfully communicate with the MQTT server through the reverse proxy.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ol&gt;</description><category>location</category><category>metadata</category><category>mobile</category><category>owntracks</category><category>selfhosting</category><guid>https://bgstack15.ddns.net/blog/posts/2025/11/11/trying-owntracks-to-track-my-mobile-devices/</guid><pubDate>Tue, 11 Nov 2025 13:40:00 GMT</pubDate></item><item><title>Luanti serverlist self-hosted in Docker</title><link>https://bgstack15.ddns.net/blog/posts/2025/04/29/luanti-serverlist-self-hosted-in-docker/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;The official &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/servers.luanti.org/"&gt;Luanti serverlist&lt;/a&gt; is really cool, and is &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/github.com/luanti-org/serverlist/"&gt;free software&lt;/a&gt;! The game client uses this list to show you the public instances. I &lt;a href="https://bgstack15.ddns.net/blog/cgit/luanti/serverlist"&gt;forked it&lt;/a&gt; so I could make it work better with the arbitrary server addresses, and I built a docker container for it. I needed it to accept a &lt;code&gt;server_address = dockerhost.ipa.example.com$30001&lt;/code&gt; so that it would publish that hostname and port, rather than the connected IP address (an internal docker one) of 172.24.0.2 with port 30000 like the container always runs. This means my serverlist trusts the entry coming from the Luanti instance and does not do anything with the actual requester IP address, so it's not as secure.&lt;/p&gt;
&lt;p&gt;No, it's not published on hub.docker.com or anywhere else. But it's pretty simple to build.&lt;/p&gt;
&lt;p&gt;To build your own docker image with the static files, and no nodejs components, run this command in the repo directory, in &lt;a href="https://bgstack15.ddns.net/blog/cgit/luanti/serverlist/tree/?h=dev/add-docker"&gt;my branch&lt;/a&gt;. My branch includes the generated servers.js downloaded from the public instance which for some reason took a whole node project to build?! I hate nodepm and never figured out how to use it, and I suppose this docker container is now overkill for just a small Flask project, but it fits nicely with my other docker infrastructure at this point.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker build . -- tag luantiserverlist
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Adjust docker-compose.yml if necessary, and mkdir &lt;code&gt;/home/luanti/serverlist/run&lt;/code&gt;. The initial assets will be copied to this volume, for you adjust afterwards. Then you can run docker-compose.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;docker-compose up -d
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The included &lt;code&gt;docker-compose.yml&lt;/code&gt; exposes port 8082.&lt;/p&gt;
&lt;p&gt;For an easy reverse proxy in apache httpd, to serve at &lt;code&gt;https://reverseproxy.example.com/games/luantiserverlist&lt;/code&gt; which you can place in your minetest.conf variable &lt;code&gt;serverlist_url&lt;/code&gt;.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;# Inside your virtual host.
ProxyPass        /games/luantiserverlist http://dockerhost.int.example.com:8082/
ProxyPassReverse /games/luantiserverlist http://dockerhost.int.example.com:8082/
&lt;span class="nt"&gt;&amp;lt;Location&lt;/span&gt; &lt;span class="err"&gt;"/games/luantiserverlist"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
   RequestHeader append X-Forwarded-Prefix "/games/luantiserverlist/"
&lt;span class="nt"&gt;&amp;lt;/Location&amp;gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And then you can configure servers and clients to use this value.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;serverlist_url = http://webserver.ipa.example.com/games/luantiserverlist/
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;It's really great to be able to list your own servers with pretty names and descriptions!&lt;/p&gt;
&lt;p&gt;Praise the Lord for people who are willing to make FLOSS. I doubt many people will want my modifications, but they're there for anyone who would like it.&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/medium.com/@geeekfa/dockerizing-a-python-flask-app-a-step-by-step-guide-to-containerizing-your-web-application-d0f123159ba2"&gt;Dockerizing a Python Flask App: A Step-by-Step Guide to Containerizing Your Web Application | by GeeekFa | Medium&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description><category>game</category><category>luanti</category><category>selfhosting</category><guid>https://bgstack15.ddns.net/blog/posts/2025/04/29/luanti-serverlist-self-hosted-in-docker/</guid><pubDate>Tue, 29 Apr 2025 12:46:00 GMT</pubDate></item><item><title>Hosting a Flatpak repo</title><link>https://bgstack15.ddns.net/blog/posts/2025/04/17/hosting-a-flatpak-repo/</link><dc:creator>bgstack15</dc:creator><description>&lt;div&gt;&lt;p&gt;In the last post, I explained how I &lt;a href="https://bgstack15.ddns.net/blog/posts/2025/04/13/building-my-first-flatpak/"&gt;built my first flatpak&lt;/a&gt;! So now that I have a flatpak I want to distribute to my users, how do I do that? A &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/docs.flatpak.org/en/latest/hosting-a-repository.html"&gt;web-based repository&lt;/a&gt;, like everything else!&lt;/p&gt;
&lt;h2&gt;Preparing the repo&lt;/h2&gt;
&lt;p&gt;A flatpak repo is just a web directory. For one of these hipster modern techs, they made a good decision for a web repo!&lt;/p&gt;
&lt;p&gt;I built a custom &lt;code&gt;internal.flatpakrepo&lt;/code&gt; file, and for convenience I placed in in that same directory, but it doesn't have to be there.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;[Flatpak Repo]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;Title&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Internal Flatpak Repo&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;Url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;http://server3/internal/repo/flatpak/&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;Homepage&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;http://server3/internal/repo/flatpak/&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;Comment&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;Local flatpak repo&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;Description&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;All my local flatpaks go here&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;Icon&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;http://server3/internal/repo/flatpak/icon.png&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;At least Gnome Software does not seem to use the repo icon, so I guess my chasing one down was pointless, but whatever. I think it works better with a 128x128 icon for the repo, and letting Gnome Software cache it a few times before you expect it to see it (?), but sometimes it works.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/posts/2025/04/17/hosting-a-flatpak-repo/"&gt;Read more…&lt;/a&gt; (5 min remaining to read)&lt;/p&gt;&lt;/div&gt;</description><category>flatpak</category><category>packaging</category><category>repo</category><category>selfhosting</category><guid>https://bgstack15.ddns.net/blog/posts/2025/04/17/hosting-a-flatpak-repo/</guid><pubDate>Thu, 17 Apr 2025 12:33:00 GMT</pubDate></item><item><title>Self-host a pip repo</title><link>https://bgstack15.ddns.net/blog/posts/2025/01/11/self-host-a-pip-repo/</link><dc:creator>bgstack15</dc:creator><description>&lt;h2&gt;tl;dr&lt;/h2&gt;
&lt;p&gt;&lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/packaging.python.org/en/latest/guides/hosting-your-own-index/"&gt;Use apache httpd with autoindex on&lt;/a&gt;. In the module project, make file &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/packaging.python.org/en/latest/tutorials/packaging-projects/#configuring-metadata"&gt;pyproject.toml&lt;/a&gt;. Run &lt;code&gt;python3 -m build&lt;/code&gt; and take the &lt;code&gt;dist/*.tar.gz&lt;/code&gt; files and place in the apache web directories underneath a &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/packaging.python.org/en/latest/specifications/name-normalization/#name-normalization"&gt;normalized&lt;/a&gt; directory name.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/var/www/&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;python/&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tkstackrpms/&lt;/code&gt;&lt;ul&gt;
&lt;li&gt;&lt;code&gt;tkstackrpms-0.0.1.tar.gz&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;tkstackrpms-0.0.2.tar.gz&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;h2&gt;Using your self-hosted repo&lt;/h2&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;pip install --extra-index-url http://server3/internal/repo/python/ --trusted-host server3 tkstackrpms
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or load into &lt;code&gt;~/.config/pip/pip.conf&lt;/code&gt; the following.&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span class="k"&gt;[global]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;trusted-host&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;server3&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;extra-index-url&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;http://server3/internal/repo/python&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="na"&gt;https://www.example.com/internal/repo/python&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/pre&gt;&lt;/div&gt;

&lt;h2&gt;Narrative&lt;/h2&gt;
&lt;p&gt;I have a small &lt;a href="https://bgstack15.ddns.net/blog/cgit/python3-tkstackrpms"&gt;python module&lt;/a&gt; I wrote, and I want it to be available to me inside a python virtual environment (venv). Since I don't really want to go through whatever rigamarole would be required for a public package, and not sure I want to burden the world with my creation, I wanted to self-host a repository.&lt;/p&gt;
&lt;p&gt;Inside a venv one can't just install my &lt;a href="https://bgstack15.ddns.net/blog/outbound/https:/build.opensuse.org/package/show/home:bgstack15/python3-tkstackrpms"&gt;dpkg&lt;/a&gt;, so I needed a proper pip web repository.&lt;/p&gt;
&lt;p&gt;Thankfully, the process is well documented and works with some basic httpd configuration I already was using!&lt;/p&gt;
&lt;h2&gt;References&lt;/h2&gt;
&lt;p&gt;See all links in-line.&lt;/p&gt;</description><category>pip</category><category>python</category><category>selfhosting</category><guid>https://bgstack15.ddns.net/blog/posts/2025/01/11/self-host-a-pip-repo/</guid><pubDate>Sat, 11 Jan 2025 14:28:00 GMT</pubDate></item><item><title>Thoughts on self-hosted youtube alternatives</title><link>https://bgstack15.ddns.net/blog/posts/2022/07/24/thoughts-on-self-hosted-youtube-alternatives/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;The whole topic of self-hosted youtube alternatives is rather scant on the Internet, which surprised me.&lt;/p&gt;
&lt;p&gt;I found a nice &lt;a href="https://github.com/alexta69/metube"&gt;web-based yt-dlp frontend&lt;/a&gt;! I have a single Docker server for other purposes, so it was nice to play around with this metube. Ultimately it wasn't better than running yt-dlp in a terminal and dragging links into that command to append the url to the command.&lt;/p&gt;
&lt;p&gt;And for the viewing frontend, I tried &lt;a href="https://git.mills.io/prologic/tube"&gt;https://git.mills.io/prologic/tube&lt;/a&gt; which sounded so promising! The video upload operations never completed for me. I think it was trying to encode the videos (transcode?) but it never actually populated the web page with contents even after ffmpeg stopped running.&lt;/p&gt;
&lt;p&gt;So I then tried &lt;a href="https://github.com/mediacms-io/mediacms/"&gt;MediaCMS&lt;/a&gt; which I really, really wanted to like. It's a Django (python) app, which I have no experience with. I was unable to get this reverse-proxied behind Apache httpd under a virtual path (or prefix, i.e., https://example.com/media/). I gave up and then used a different port number, so all the traffic on port 1285 went to the application.
This one worked with uploaded videos. I had to change a few settings in the &lt;code&gt;deploy/docker/local_settings.py&lt;/code&gt;:&lt;/p&gt;
&lt;div class="code"&gt;&lt;pre class="code literal-block"&gt;MINIMUM_RESOLUTIONS_TO_ENCODE = [240, 360, 1080]
USE_X_FORWARDED_HOST = True
SECURE_PROXY_SSL_HEADER = ('HTTP_X_FORWARDED_PROTO', 'https')
&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The last two are the bog-standard Django reverse-proxy instructions that deal with https. This is needed for any proxying tasks. I removed my manipulated STATIC_URL, MEDIA_URL, and FORCE_SCRIPT_NAME components which never actually completely worked.&lt;/p&gt;
&lt;p&gt;The MediaCMS web presentation looks slick. With the 1080 minimum resolution (which ended up producing a file twice as large as the 1080p files I uploaded), it was acceptable. There is even a little button over the video for "Cast video." From a mobile browser, the cast failed to send to my Chromecast. From a desktop's chromium, it did work to cast to a Chromecast. It started as screen mirroring, and then it asked me if I wanted to send just the video.&lt;/p&gt;
&lt;p&gt;So the usability was missing a little bit.&lt;/p&gt;
&lt;p&gt;And none of this was actually better than Jellyfin, and also just visiting the files over nfs, except the awesome youtube interface. The quadruple files per video was a little excessive but storage is cheap these days, right?&lt;/p&gt;</description><category>experiment</category><category>selfhosting</category><category>youtube</category><guid>https://bgstack15.ddns.net/blog/posts/2022/07/24/thoughts-on-self-hosted-youtube-alternatives/</guid><pubDate>Sun, 24 Jul 2022 12:41:04 GMT</pubDate></item><item><title>Calendar solution for internal network</title><link>https://bgstack15.ddns.net/blog/posts/2022/05/21/calendar-solution-for-internal-network/</link><dc:creator>bgstack15</dc:creator><description>&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;As part of my efforts to de-google my life, the Calendar solution is a fully self-hosted and FLOSS project. This project uses Radicale caldav server, which is already packaged for EL7 (but I repackage a newer version). The project also uses InfCloud which is a web client for caldav, which is loosely hardcoded to use this existing radicale instance.&lt;/p&gt;
&lt;p&gt;Additional components include the F-droid packages of davX⁵ (carddav sync utility) and ETar, a calendar client.&lt;/p&gt;
&lt;h3&gt;Prequisites&lt;/h3&gt;
&lt;p&gt;Apache httpd is installed. TLS certificates are in use, to protect the password traffic.&lt;/p&gt;
&lt;h3&gt;Building&lt;/h3&gt;
&lt;p&gt;CentOS 7 provides radicale 1.1, which is not the current version. I adapted the radicale and various python dependencies from Fedora, and also wrote the rpm spec for InfCloud. A copy of Git repository for &lt;a href="https://gitlab.com/bgstack15/build-radicale-el7.git"&gt;build-radicale-el7&lt;/a&gt; exists here. See &lt;a href="https://gitlab.com/bgstack15/build-radicale-el7"&gt;build-radicale-el7/README.md&lt;/a&gt; for this whole process. NOTE: this includes one patch that I wrote to allow automatic login using the reverse proxy apache ldap authentication.&lt;/p&gt;
&lt;p&gt;I established a &lt;a href="https://copr.fedorainfracloud.org/coprs/bgstack15/radicale-el7/"&gt;copr&lt;/a&gt; to hold the rpm packages.&lt;/p&gt;
&lt;h3&gt;Installing on production&lt;/h3&gt;
&lt;p&gt;On server1, I ran a number of steps which are also documented in the [main server log][3].&lt;/p&gt;
&lt;p&gt;Add the copr repo.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;curl https://copr.fedorainfracloud.org/coprs/bgstack15/radicale-el7/repo/epel-7/bgstack15-radicale-el7-epel-7.repo | sudo tee /etc/yum.repos.d/bgstack15-radicale-el7.repo
sudo yum install radicale3 infcloud
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Customize &lt;code&gt;/etc/radicale/config&lt;/code&gt; and &lt;code&gt;/etc/infcloud/config.js&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Add redirects for my http virtual host in httpd:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;# &lt;span class="nv"&gt;Force&lt;/span&gt; &lt;span class="nv"&gt;https&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;these&lt;/span&gt; &lt;span class="nv"&gt;pages&lt;/span&gt; &lt;span class="nv"&gt;or&lt;/span&gt; &lt;span class="nv"&gt;apps&lt;/span&gt;
&lt;span class="nv"&gt;RewriteCond&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;{&lt;span class="nv"&gt;HTTPS&lt;/span&gt;} &lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;
&lt;span class="nv"&gt;Redirect&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;radicale&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;www&lt;/span&gt;.&lt;span class="nv"&gt;example&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;radicale&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;span class="nv"&gt;RewriteCond&lt;/span&gt; &lt;span class="o"&gt;%&lt;/span&gt;{&lt;span class="nv"&gt;HTTPS&lt;/span&gt;} &lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="nv"&gt;on&lt;/span&gt;
&lt;span class="nv"&gt;Redirect&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;calendar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;www&lt;/span&gt;.&lt;span class="nv"&gt;example&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;calendar&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Also add useful VirtualHost contents to my apache config file &lt;code&gt;ssl-common.cnf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;# &lt;span class="mi"&gt;2022&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;05&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;17&lt;/span&gt;
#&lt;span class="nv"&gt;ServerName&lt;/span&gt; &lt;span class="nv"&gt;calendar&lt;/span&gt;.&lt;span class="nv"&gt;example&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;
&lt;span class="nv"&gt;RewriteEngine&lt;/span&gt; &lt;span class="nv"&gt;On&lt;/span&gt;
&lt;span class="nv"&gt;RewriteRule&lt;/span&gt; &lt;span class="o"&gt;^/&lt;/span&gt;&lt;span class="nv"&gt;radicale&lt;/span&gt;$ &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;radicale&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; [&lt;span class="nv"&gt;R&lt;/span&gt;,&lt;span class="nv"&gt;L&lt;/span&gt;]
&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="nv"&gt;Location&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/radicale/&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
   &lt;span class="nv"&gt;ProxyPreserveHost&lt;/span&gt; &lt;span class="nv"&gt;On&lt;/span&gt;
   &lt;span class="nv"&gt;Order&lt;/span&gt; &lt;span class="nv"&gt;deny&lt;/span&gt;,&lt;span class="nv"&gt;allow&lt;/span&gt;
   &lt;span class="nv"&gt;Deny&lt;/span&gt; &lt;span class="nv"&gt;from&lt;/span&gt; &lt;span class="nv"&gt;all&lt;/span&gt;
   &lt;span class="nv"&gt;AuthType&lt;/span&gt; &lt;span class="nv"&gt;Basic&lt;/span&gt;
   &lt;span class="nv"&gt;AuthName&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;LDAP protected&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nv"&gt;AuthBasicProvider&lt;/span&gt; &lt;span class="nv"&gt;ldap&lt;/span&gt;
   &lt;span class="nv"&gt;AuthLDAPGroupAttribute&lt;/span&gt; &lt;span class="nv"&gt;member&lt;/span&gt;
   &lt;span class="nv"&gt;AuthLDAPSubGroupClass&lt;/span&gt; &lt;span class="nv"&gt;group&lt;/span&gt;
   # &lt;span class="k"&gt;If&lt;/span&gt; &lt;span class="nv"&gt;anonymous&lt;/span&gt; &lt;span class="nv"&gt;search&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;disabled&lt;/span&gt;, &lt;span class="nv"&gt;provide&lt;/span&gt; &lt;span class="nv"&gt;dn&lt;/span&gt; &lt;span class="nv"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;pw&lt;/span&gt;.
   #&lt;span class="nv"&gt;AuthLDAPBindDN&lt;/span&gt; &lt;span class="nv"&gt;uid&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;service&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;account&lt;/span&gt;,&lt;span class="nv"&gt;cn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;users&lt;/span&gt;,&lt;span class="nv"&gt;cn&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;accounts&lt;/span&gt;,&lt;span class="nv"&gt;dc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;ipa&lt;/span&gt;,&lt;span class="nv"&gt;dc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;example&lt;/span&gt;,&lt;span class="nv"&gt;dc&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;com&lt;/span&gt;
   #&lt;span class="nv"&gt;AuthLDAPBindPassword&lt;/span&gt; &lt;span class="nv"&gt;mypw&lt;/span&gt;
   &lt;span class="nv"&gt;AuthLDAPGroupAttributeIsDN&lt;/span&gt; &lt;span class="nv"&gt;On&lt;/span&gt;
   &lt;span class="nv"&gt;AuthLDAPURL&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ldaps://dns1.ipa.internal.com:636 dns2.ipa.internal.com:636/cn=users,cn=accounts,dc=ipa,dc=internal,dc=com?uid,memberof,gecos?sub?(objectClass=person)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   #?&lt;span class="nv"&gt;sub&lt;/span&gt;?&lt;span class="ss"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;objectClass&lt;/span&gt;&lt;span class="o"&gt;=*&lt;/span&gt;&lt;span class="ss"&gt;)&lt;/span&gt;
   &lt;span class="nv"&gt;Require&lt;/span&gt; &lt;span class="nv"&gt;valid&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;user&lt;/span&gt;
   &lt;span class="nv"&gt;Satisfy&lt;/span&gt; &lt;span class="nv"&gt;any&lt;/span&gt;
   # &lt;span class="nv"&gt;My&lt;/span&gt; &lt;span class="nv"&gt;radical&lt;/span&gt; &lt;span class="nv"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;up&lt;/span&gt; &lt;span class="nv"&gt;uses&lt;/span&gt; &lt;span class="nv"&gt;HTTP_X_REMOTE_USER&lt;/span&gt; &lt;span class="nv"&gt;as&lt;/span&gt; &lt;span class="nv"&gt;username&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;authentication&lt;/span&gt;
   &lt;span class="nv"&gt;RequestHeader&lt;/span&gt; &lt;span class="nv"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;X_REMOTE_USER&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%{AUTHENTICATE_uid}e&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   # &lt;span class="nv"&gt;This&lt;/span&gt; &lt;span class="nv"&gt;does&lt;/span&gt; &lt;span class="nv"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;populate&lt;/span&gt; &lt;span class="nv"&gt;correctly&lt;/span&gt;. &lt;span class="nv"&gt;Probably&lt;/span&gt; &lt;span class="nv"&gt;the&lt;/span&gt; &lt;span class="nv"&gt;ldap&lt;/span&gt; &lt;span class="nv"&gt;memberOf&lt;/span&gt; &lt;span class="nv"&gt;attribute&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;derived&lt;/span&gt; &lt;span class="nv"&gt;and&lt;/span&gt; &lt;span class="nv"&gt;not&lt;/span&gt; &lt;span class="nv"&gt;real&lt;/span&gt;?
   &lt;span class="nv"&gt;RequestHeader&lt;/span&gt; &lt;span class="nv"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;X_GROUPS&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%{AUTHENTICATE_memberOf}e&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   # &lt;span class="nv"&gt;This&lt;/span&gt; &lt;span class="nv"&gt;populates&lt;/span&gt; &lt;span class="nv"&gt;correctly&lt;/span&gt;
   &lt;span class="nv"&gt;RequestHeader&lt;/span&gt; &lt;span class="nv"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;X_GECOS&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;%{AUTHENTICATE_gecos}e&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nv"&gt;ProxyPass&lt;/span&gt;        &lt;span class="nv"&gt;http&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;localhost&lt;/span&gt;:&lt;span class="mi"&gt;5232&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt; &lt;span class="nv"&gt;retry&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="nv"&gt;connectiontimeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt; &lt;span class="nb"&gt;timeout&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="mi"&gt;300&lt;/span&gt;
   &lt;span class="nv"&gt;ProxyPassReverse&lt;/span&gt; &lt;span class="nv"&gt;http&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;localhost&lt;/span&gt;:&lt;span class="mi"&gt;5232&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;
   &lt;span class="nv"&gt;RequestHeader&lt;/span&gt;    &lt;span class="nv"&gt;set&lt;/span&gt; &lt;span class="nv"&gt;X&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;Script&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;Name&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;radicale&lt;/span&gt;
&lt;span class="o"&gt;&amp;lt;/&lt;/span&gt;&lt;span class="nv"&gt;Location&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I customized the storage of calendars (aka collections) to be on the main storage area:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mkdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;server1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;shares&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Support&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Systems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;server1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;radicale&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mv&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;radicale&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;server1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;shares&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Support&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Systems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;server1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;radicale&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;server1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;shares&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;public&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Support&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;Systems&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;server1&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;radicale&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;lib&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;radicale&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;collections&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;semanage&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;fcontext&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;radicale_var_lib_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;'/var/server1/shares/public/Support/Systems/server1/var/lib/radicale/collections(/.*)?'&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I also added all these aforementioned config files to the host-bup config file.&lt;/p&gt;
&lt;p&gt;Start and enable radicale service.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo systemctl enable radicale
sudo systemctl start radicale
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Make a symlink in the web root directory that points to the infcloud contents.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ln&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;usr&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;share&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;infcloud&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;radicale_infcloud&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;web&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;calendar&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Making good config choices&lt;/h3&gt;
&lt;p&gt;In order for InfCloud to save which calendars are enabled/visible by default, you need to turn "settingsAccount" on in config.js. This attribute causes InfCloud to store some metadata about the user choices on the caldav server (Radicale). Without this feature, the InfCloud user cannot even change which calendars are visible!&lt;/p&gt;
&lt;h3&gt;Summary of associated files&lt;/h3&gt;
&lt;p&gt;On server1, the production server:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;/etc/radicale/config&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/infcloud/config.js&lt;/code&gt; symlinked to with /var/www/calendar/&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/etc/infcloud/cache.manifest&lt;/code&gt; symlinked to within /var/www/html/calendar/&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/usr/sbin/update-infcloud-cache&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;/var/www/html/calendar&lt;/code&gt; is a symlink to &lt;code&gt;/usr/share/infcloud/radicale_infcloud/web&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Operations&lt;/h3&gt;
&lt;p&gt;Some tasks that will happen over time are listed here.&lt;/p&gt;
&lt;h4&gt;Modifying InfCloud files or config&lt;/h4&gt;
&lt;p&gt;After making any changes to anything for InfCloud (the web client), you need to update the cache manifest file. It is possible that touching the file works, but a method for updating the version number in the file is with script:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo update-infcloud-cache
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Controling collections&lt;/h4&gt;
&lt;p&gt;To add, modify, or remove personal collections (calendars, address books, and todo lists), visit &lt;a href="https://www.example.com/radicale/"&gt;https://www.example.com/radicale/&lt;/a&gt;. Log in with a domain credential.&lt;/p&gt;
&lt;h4&gt;Adding a client&lt;/h4&gt;
&lt;p&gt;To connect a carddav/caldav client to the Calendar service, use url &lt;a href="https://www.example.com/radicale/"&gt;https://www.example.com/radicale/&lt;/a&gt; and select "Use username and password."&lt;/p&gt;
&lt;h4&gt;Using a web calendar&lt;/h4&gt;
&lt;p&gt;To use a rich web client, visit &lt;a href="https://www.example.com/calendar/"&gt;https://www.example.com/calendar/&lt;/a&gt; and type in your domain username and password.&lt;/p&gt;
&lt;h5&gt;Sending invitations for event from web calendar&lt;/h5&gt;
&lt;p&gt;In the web client, select an event. Select button "Download," which saves a .ics file. Send this .ics file in your preferred mail client to your guests.&lt;/p&gt;
&lt;h5&gt;Importing event to web calendar&lt;/h5&gt;
&lt;p&gt;Feature not implemented yet. Gotta say unh!&lt;/p&gt;
&lt;h4&gt;Sharing calendar with other Radicale user&lt;/h4&gt;
&lt;p&gt;This step has to happen first, before the following Sharing operations can work.&lt;/p&gt;
&lt;p&gt;An admin has to modify file storage:&lt;code&gt;/etc/radicale/rights&lt;/code&gt; and add some steps. Create one rule per &lt;strong&gt;[uniquely-named-section]&lt;/strong&gt;. Use uppercase permission letters for a "root" collection, i.e., a username. Use lowercase letters for any child collections. The uuid of a collection is required: the pretty name is not accepted.&lt;/p&gt;
&lt;p&gt;The following is a way to allow all authenticated users to enumerate the items owned by domainjoin, and also read all those items.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[public-principal]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;user: .+&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;collection: domainjoin&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;permissions: rRi&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;[public-calendars]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;user: .+&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;collection: domainjoin/[^/]+&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;permissions: rRi&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Adding a "w" or "W" as appropriate to the &lt;em&gt;permissions:&lt;/em&gt; entry would enable write access. Another example, for username2 to write to a specific bgstack15 calendar:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[rule1]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;user: username2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;collection: bgstack15&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;permissions: R&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="k"&gt;[rule2]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;user: username2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;collection: bgstack15/68cb9dbf-7546-8023-ca4c-c69bc64918a2&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="na"&gt;permissions: rwi&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;It is probable that read access to the root collection is required in order for the web calendar to be able to enumerate the one shared calendar, but further experimentation should be done.&lt;/p&gt;
&lt;h4&gt;Opening a shared calendar in web calendar&lt;/h4&gt;
&lt;p&gt;Unfortunately this so far is only known to work by modifying &lt;code&gt;/etc/infcloud/config.js&lt;/code&gt; which requires admin access to server1. If all users of the web calendar should be able to view/edit a collection, add the owning user to attribute &lt;code&gt;additionalResources: ['user5']&lt;/code&gt; inside var &lt;strong&gt;globalNetworkCheckSettings&lt;/strong&gt;. In this example, user5 owns a shared collection, as defined by heading &lt;em&gt;Sharing calendar with other Radicale user&lt;/em&gt;. Of course, after modifying config.js, run &lt;code&gt;update-infcloud-cache&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;For a specific login to access another specific login root collection (because InfCloud relies on enumerating collections underneath a root collection, i.e., user, rather than pointing to a specific collectioN), you can use the custom stackrpms attribute &lt;strong&gt;perUserAdditionalResources&lt;/strong&gt; such as this example:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;globalNetworkCheckSettings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;perUserAdditionalResources&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"bgstack15"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"username2"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="s2"&gt;"username2"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;allowed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"bgstack15"&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Now, the shared collections should populate in the web calendar. If the logged-in user does not have access to this resource, an unfixable and unhideable exclamation mark "!" will appear in the web calendar in the left-hand side menu. It will not be clear to the user what has gone wrong.&lt;/p&gt;
&lt;h4&gt;Opening a shared calendar with davX⁵&lt;/h4&gt;
&lt;p&gt;Unfortunately the only plan for accessing shared calendars is to set up a new connection in DavX⁵ with the exact url of the target calendar, e.g. &lt;strong&gt;https://www.example.com/radicale/domainjoin/338119a7-3556-0a9b-67ab-be391db1ae77/&lt;/strong&gt; which is selectable for copy-paste when the owning user visits &lt;a href="https://www.example.com/radicale/"&gt;/radicale/&lt;/a&gt; and enumerates his collections.&lt;/p&gt;
&lt;p&gt;This task will make a new entry that enumerates that logged-in user collections, and also this one exact collection.&lt;/p&gt;
&lt;h3&gt;Future improvements&lt;/h3&gt;
&lt;p&gt;Investigate more calendar sharing.
Migrate address books.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;h4&gt;Internal files&lt;/h4&gt;
&lt;p&gt;[3]: server1 history log&lt;/p&gt;
&lt;h4&gt;Git repositories&lt;/h4&gt;
&lt;p&gt;[6]: &lt;a href="https://gitlab.com/bgstack15/radicale_auth_ldap.git"&gt;https://gitlab.com/bgstack15/radicale_auth_ldap.git&lt;/a&gt; I ended up not using this, but it is worthy of mentioning.&lt;/p&gt;
&lt;h4&gt;Weblinks&lt;/h4&gt;
&lt;blockquote&gt;
&lt;p&gt;conaclos
 An interesting alternative is Radicale &lt;a href="https://bgstack15.ddns.net/blog/posts/2022/05/21/calendar-solution-for-internal-network/research-caldav.txt"&gt;1&lt;/a&gt;. Both are very lightweight. I mainly chose Radicale over Baïkal because it is written in Python. On the client side DAVx⁵ &lt;a href="https://bgstack15.ddns.net/blog/posts/2022/05/21/calendar-solution-for-internal-network/replace-google-research.txt"&gt;2&lt;/a&gt; do a good job.
&lt;a href="https://bgstack15.ddns.net/blog/posts/2022/05/21/calendar-solution-for-internal-network/research-caldav.txt"&gt;1&lt;/a&gt; https://radicale.org/v3.html &lt;a href="https://bgstack15.ddns.net/blog/posts/2022/05/21/calendar-solution-for-internal-network/replace-google-research.txt"&gt;2&lt;/a&gt; https://www.davx5.com/
  cube00
  I've been using Radicale for a few years now and it has been fantastic. Extremely lightweight but also quite flexible with its permissions model since we have a shared family calendar.
  The backend storage is simply ics/vcf files and while I'm sure it's not the most efficient if you had a large number of users, for our small group it's been perfect and very satisfying knowing your data is there in plain text files.
  Although if I'm honest I'm just cheap and wanted to get by on the smallest VM offered by my cloud provider and NextCloud was too demanding for that.
    jamessb
    &amp;gt; Extremely lightweight but also quite flexible with its permissions model since we have a shared family calendar.
    How are you doing this?
    A while ago I skimmed the documentation for a couple of CalDAV servers to try and figure out how I could self-host a shared calendar, but couldn't see an easy way to do this.
    I've just done some more searching, and it seems there are two suggested ways to do this with Radicale:
    * create a separate account for the shared calendar, and tell everyone who needs write access the password
    * create the calendar in one use's directory, and add a symlink to it in the user directories for any other users who need write access.
    Both of which seem like a bit of hack compared to bring able to explicitly state that a list of users have write access to a calendar in a config file or through a UI.
      cube00
      I created a collection with the name of our domain name and then used this example&lt;a href="https://bgstack15.ddns.net/blog/posts/2022/05/21/calendar-solution-for-internal-network/research-caldav.txt"&gt;1&lt;/a&gt; to regex the domain out of the user's login email address to allow them access to the shared collection.
      &lt;a href="https://bgstack15.ddns.net/blog/posts/2022/05/21/calendar-solution-for-internal-network/research-caldav.txt"&gt;1&lt;/a&gt;: https://github.com/Kozea/Radicale/blob/497b5141b066d266c318e...&lt;/p&gt;
&lt;h2&gt;Example: Grant users of the form user@domain.tld read access to the&lt;/h2&gt;
&lt;h2&gt;collection "domain.tld"&lt;/h2&gt;
&lt;h2&gt;Allow reading the domain collection&lt;/h2&gt;
&lt;h2&gt;[read-domain-principal]&lt;/h2&gt;
&lt;h2&gt;user: .+@([^@]+)&lt;/h2&gt;
&lt;h2&gt;collection:&lt;/h2&gt;
&lt;h2&gt;permissions: R&lt;/h2&gt;
&lt;h2&gt;Allow reading all calendars and address books that are direct children of&lt;/h2&gt;
&lt;h2&gt;the domain collection&lt;/h2&gt;
&lt;h2&gt;[read-domain-calendars]&lt;/h2&gt;
&lt;h2&gt;user: .+@([^@]+)&lt;/h2&gt;
&lt;h2&gt;collection: {0}/[^/]+&lt;/h2&gt;
&lt;h2&gt;permissions: r&lt;/h2&gt;
&lt;/blockquote&gt;</description><category>calendar</category><category>floss</category><category>infcloud</category><category>radicale</category><category>selfhosting</category><guid>https://bgstack15.ddns.net/blog/posts/2022/05/21/calendar-solution-for-internal-network/</guid><pubDate>Sat, 21 May 2022 12:58:53 GMT</pubDate></item><item><title>Mirror a copr, all architectures and releases and versions</title><link>https://bgstack15.ddns.net/blog/posts/2021/08/20/mirror-a-copr-all-architectures-and-releases-and-versions/</link><dc:creator>bgstack15</dc:creator><description>&lt;p&gt;&lt;a href="https://gitlab.com/bgstack15/coprmirror"&gt;coprmirror&lt;/a&gt; is my yum mirror
solution, with a wrapper to mirror specifically a named
&lt;a href="https://copr.fedorainfracloud.org/coprs/"&gt;COPR&lt;/a&gt; repository.&lt;/p&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://copr.fedorainfracloud.org/coprs/"&gt;COPR&lt;/a&gt; is a distro-run community
offering that lets users build yum/dnf repositories with their own software
(primarily if not exclusively in rpm format). COPR performs the builds, and
then hosts the binary and source rpms for client machines. My project today
downloads using native GNU/Linux tools the yum repositories that collectively
make up a COPR, so each release-releasever-basearch triplet. The end goal is
to have a local copy of the entire current yum repos. This does not copy the
build assets or log files; just what a yum repository defines and also the gpg
public key. Notably this utility needs the yum python packages present only
for evaluating yum variables in the inurl (baseurl from a .repo file), so if
you have a string literal as the inurl value, you can run this on a system
that does not have yum installed.&lt;/p&gt;
&lt;h3&gt;Using&lt;/h3&gt;
&lt;p&gt;Configure coprmirror.conf from the provided .example file, and then run:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;COPRMIRROR_CONF=coprmirror.conf VERBOSE=1 DEBUG=1 ./coprmirror.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Upstream&lt;/h3&gt;
&lt;p&gt;Original content The get_file function was improved after being imported from
my &lt;a href="https://gitlab.com/bgstack15/former-gists/-/blob/master/obsmirror.sh/obsmirror.sh"&gt;Reference 1&lt;/a&gt; script.&lt;/p&gt;
&lt;h3&gt;Alternatives&lt;/h3&gt;
&lt;p&gt;I felt like ansible and system are overkill, but if you like those, this is
perfect for you: &lt;a href="https://github.com/ganto/ansible-copr_reposync"&gt;https://github.com/ganto/ansible-copr_reposync&lt;/a&gt;&lt;/p&gt;
&lt;h3&gt;Dependencies&lt;/h3&gt;
&lt;p&gt;wget, grep, awk, sed, jq&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://gitlab.com/bgstack15/former-gists/-/blob/master/obsmirror.sh/obsmirror.sh"&gt;obsmirror&lt;/a&gt; &lt;a href="https://bgstack15.ddns.net/blog/posts/2020/03/11/mirror-an-obs-repository-locally-update-1/"&gt;Mirror an OBS repository
locally — update 1&lt;/a&gt; [this blog]&lt;/p&gt;</description><category>copr</category><category>mirror</category><category>selfhosting</category><category>yum</category><guid>https://bgstack15.ddns.net/blog/posts/2021/08/20/mirror-a-copr-all-architectures-and-releases-and-versions/</guid><pubDate>Fri, 20 Aug 2021 12:44:20 GMT</pubDate></item><item><title>Populating my new cgit instance</title><link>https://bgstack15.ddns.net/blog/posts/2021/04/25/populating-my-new-cgit-instance/</link><dc:creator>bgstack15</dc:creator><description>&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;Gitlab is the curent source of truth for all repos, except for the secure data
stored locally at /mnt/public/packages. To prepare my &lt;a href="https://bgstack15.ddns.net/blog/posts/2021/04/21/cgit-solution-for-my-network/"&gt;on-prem git
repos&lt;/a&gt;, I need to be be able to synchronize my repositories from the
sources of truth. This process sets up the bare repos on the main git and web
server, and sets up the sync-location git repos on any VM.&lt;/p&gt;
&lt;h3&gt;Preparing list assets&lt;/h3&gt;
&lt;p&gt;We need the csv lists that show the old and new locations.&lt;/p&gt;
&lt;h4&gt;Generating gitlab token&lt;/h4&gt;
&lt;p&gt;Visit gitlab.com in web browser, sign in, and visit "Edit profile" in user
icon menu. Visit "Access Tokens" in left-side menu, and create a personal
access token that is read-only. Save the token, which will resemble string
&lt;code&gt;MnrEnTVfA-7kujMarjsG&lt;/code&gt;, to file
&lt;code&gt;/mnt/public/work/gitlab/gitlab.com.personal_access_token&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Generating list of all relevant projects&lt;/h4&gt;
&lt;p&gt;Use &lt;code&gt;generate-list.sh&lt;/code&gt; to pull the list of all my personal projects from
gitlab. It is not complete, because even &lt;a href="https://gitlab.com/dashboard/projects"&gt;Your
projects&lt;/a&gt; on gitlab shows 70 projects
total, not the 60 the API returns. So after running that file, manually add
any additional entries that should be synced.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;./generate-list.sh &amp;gt; list.csv
# manually add any additional repos to list.csv.
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;To add the destination links, run &lt;code&gt;add-dest.sh&lt;/code&gt; with redirection in and out.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&amp;lt; list.csv ./add-dest.sh &amp;gt; repos.csv
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Preparing main git destinations&lt;/h3&gt;
&lt;p&gt;With all the lists created, now prepare the final destinations of the
repositories.&lt;/p&gt;
&lt;h4&gt;Preparing blank repositories on git server&lt;/h4&gt;
&lt;p&gt;You need to make the blank repositories ahead of time due to how git-over-http
works: It only accepts pushes for extant projects. For this task, run &lt;code&gt;make-
blank.sh&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;time &amp;lt; repos.csv sh -x ./make-blank.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;On main web server, fix the permissions of these new git repos.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo chgrp apache -R /mnt/public/www/git ; sudo chmod g+rwX -R /mnt/public/www/git ;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Setting up sync locations and synchronizing&lt;/h3&gt;
&lt;p&gt;Now that the destinations are prepared, use a temporary (or at least
alternate) location to pull and then push the repositories.&lt;/p&gt;
&lt;h4&gt;Initialize sync-location git repos&lt;/h4&gt;
&lt;p&gt;VM d2-03a is the main implementation of the sync-location. This will be the
system that performs the main work of pulling all git repos and contents down,
and pushing them up to the server.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;time OUTDIR=~/dev/sync-git INFILE=/mnt/public/Support/Programs/cgit/populate/repos.csv /mnt/public/Support/Programs/cgit/populate/populate-git-remotes.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;The above command will need APPLY=1 as a variable when ready for real
execution.&lt;/p&gt;
&lt;h4&gt;Perform synchronization of all git repos&lt;/h4&gt;
&lt;p&gt;This is the main operation of this whole process. It could take some time to
execute.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;INDIR=~/dev/sync-git /mnt/public/Support/Programs/cgit/populate/sync-all.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Build initial permissions list&lt;/h4&gt;
&lt;p&gt;To restrict push access to all the new repos, run this command, and save its
output inside &lt;code&gt;/etc/git_access.conf&lt;/code&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;mindepth&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;maxdepth&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;d&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;printf&lt;/span&gt; &lt;span class="s1"&gt;'&lt;/span&gt;&lt;span class="si"&gt;%f&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s1"&gt;'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;awk&lt;/span&gt; &lt;span class="s1"&gt;'{print "Use Project "$0" &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s1"&gt;user bgstack15&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s1"&gt; &lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s1"&gt;all granted&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s1"&gt;"}'&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;sort&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;And of course an &lt;code&gt;httpd -t&lt;/code&gt; and then reload.&lt;/p&gt;
&lt;h3&gt;Appendix A: File listings&lt;/h3&gt;
&lt;h5&gt;generate-list.sh&lt;/h5&gt;
&lt;table class="codehilitetable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;
&lt;span class="normal"&gt;34&lt;/span&gt;
&lt;span class="normal"&gt;35&lt;/span&gt;
&lt;span class="normal"&gt;36&lt;/span&gt;
&lt;span class="normal"&gt;37&lt;/span&gt;
&lt;span class="normal"&gt;38&lt;/span&gt;
&lt;span class="normal"&gt;39&lt;/span&gt;
&lt;span class="normal"&gt;40&lt;/span&gt;
&lt;span class="normal"&gt;41&lt;/span&gt;
&lt;span class="normal"&gt;42&lt;/span&gt;
&lt;span class="normal"&gt;43&lt;/span&gt;
&lt;span class="normal"&gt;44&lt;/span&gt;
&lt;span class="normal"&gt;45&lt;/span&gt;
&lt;span class="normal"&gt;46&lt;/span&gt;
&lt;span class="normal"&gt;47&lt;/span&gt;
&lt;span class="normal"&gt;48&lt;/span&gt;
&lt;span class="normal"&gt;49&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2021-04-16 20:16&lt;/span&gt;
&lt;span class="c1"&gt;# Goal: generate csv to stdout of directory,origin,dest&lt;/span&gt;
&lt;span class="c1"&gt;# STEP 1&lt;/span&gt;
&lt;span class="c1"&gt;# Notes:&lt;/span&gt;
&lt;span class="c1"&gt;#    the gitlab api doesn't show the "contributed" projects in the API at all, so the output from this is incomplete. The output file will need to be curated with additional entries for projects not from my userspace.&lt;/span&gt;
&lt;span class="c1"&gt;# Dependencies:&lt;/span&gt;
&lt;span class="c1"&gt;#    Gitlab token at /mnt/public/work/gitlab/gitlab.com.personal_access_token&lt;/span&gt;
&lt;span class="c1"&gt;#    jq&lt;/span&gt;
&lt;span class="c1"&gt;# Reference: &lt;/span&gt;
&lt;span class="c1"&gt;#    https://stackoverflow.com/questions/57242240/jq-object-cannot-be-csv-formatted-only-array&lt;/span&gt;
&lt;span class="c1"&gt;#    https://stackoverflow.com/questions/32960857/how-to-convert-arbitrary-simple-json-to-csv-using-jq/32965227#32965227&lt;/span&gt;

&lt;span class="nb"&gt;test&lt;/span&gt; -z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TOKEN_FILE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;TOKEN_FILE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/mnt/public/work/gitlab/gitlab.com.personal_access_token"&lt;/span&gt;

&lt;span class="nb"&gt;test&lt;/span&gt; ! -r &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TOKEN_FILE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Fatal! Cannot find token file &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TOKEN_FILE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;. Aborted."&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;
&lt;span class="nv"&gt;TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; cat &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TOKEN_FILE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TOKEN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -qE &lt;span class="s2"&gt;"token:"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt; &lt;span class="nv"&gt;TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TOKEN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;'/^token:/{print $NF}'&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="nv"&gt;GUSER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;bgstack15

&lt;span class="c1"&gt;# Functions&lt;/span&gt;
handle_pagination&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;# call: handle_pagination "https://gitlab.com/api/v4/users/${GUSER}/projects"&lt;/span&gt;
   &lt;span class="c1"&gt;# return: stdout: a single json list of of all returned objects from all pages&lt;/span&gt;
   &lt;span class="c1"&gt;# GLOBALS USED: TOKEN&lt;/span&gt;
   &lt;span class="nv"&gt;___hp_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;1&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nv"&gt;___hp_next_link&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"dummy value"&lt;/span&gt;
   &lt;span class="nv"&gt;___hp_json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;""&lt;/span&gt;
   &lt;span class="nv"&gt;___hp_MAX&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;30&lt;/span&gt; &lt;span class="c1"&gt;# safety valve&lt;/span&gt;
   &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
   &lt;span class="nv"&gt;___hp_thisurl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;___hp_url&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="k"&gt;while&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -n &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;___hp_next_link&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; -lt &lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;___hp_MAX&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
   &lt;span class="k"&gt;do&lt;/span&gt;
      &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt;x+1&lt;span class="k"&gt;))&lt;/span&gt;
      &lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; curl --include --header &lt;span class="s2"&gt;"PRIVATE-TOKEN: &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;TOKEN&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;___hp_thisurl&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="nb"&gt;set&lt;/span&gt; +x &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;links&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;'/^link:/'&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; -x
      &lt;span class="nv"&gt;___hp_next_link&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;links&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; tr &lt;span class="s1"&gt;','&lt;/span&gt; &lt;span class="s1"&gt;'\n'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; sed -n -r -e &lt;span class="s1"&gt;'/rel="next"/{s/.*&amp;lt;!--/;s/--&amp;gt;;.*$//;p;}'&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="c1"&gt;# will be blank if next_link is not valid; that is, if this is the last page.&lt;/span&gt;
      &lt;span class="nv"&gt;___hp_thisurl&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;___hp_next_link&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
      &lt;span class="nb"&gt;set&lt;/span&gt; +x &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nv"&gt;___hp_json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;___hp_json&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;raw&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;'/^\[/'&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="nb"&gt;set&lt;/span&gt; -x
   &lt;span class="k"&gt;done&lt;/span&gt;
   &lt;span class="c1"&gt;# combine all json lists into one&lt;/span&gt;
   &lt;span class="c1"&gt;# ref: https://stackoverflow.com/a/34477713/3569534&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;___hp_json&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq --compact-output --null-input &lt;span class="s1"&gt;'reduce inputs as $in (null; . + $in)'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;# MAIN&lt;/span&gt;
&lt;span class="nv"&gt;json&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt; handle_pagination &lt;span class="s2"&gt;"https://gitlab.com/api/v4/users/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GUSER&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/projects"&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;json&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq &lt;span class="s1"&gt;'.[] | [{ web_url, path }]'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; jq -r &lt;span class="s1"&gt;'(map(keys) | add | unique) as $cols | map(. as $row|$cols|map($row[.])) as $rows | $cols, $rows[] | @csv'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;'NR == 1 {print} NR &amp;gt;1 &amp;amp;&amp;amp; !/"web_url"/{print}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;h5&gt;list.csv&lt;/h5&gt;
&lt;p&gt;Just a snippet:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ansible01&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;,&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://gitlab.com/bgstack15/ansible01&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;ansible-ssh-tunnel-for-proxy&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;,&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;https://gitlab.com/bgstack15/ansible-ssh-tunnel-for-proxy&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;gitlab&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;
&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libksba&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;gitlab&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libksba&lt;/span&gt;
&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libassuan&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;gitlab&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libassuan&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h5&gt;add-dest.sh&lt;/h5&gt;
&lt;table class="codehilitetable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2021-04-17&lt;/span&gt;
&lt;span class="c1"&gt;# STEP 2&lt;/span&gt;
&lt;span class="c1"&gt;# Goal: fix column names, and also parse to add dest column.&lt;/span&gt;
&lt;span class="nb"&gt;test&lt;/span&gt; -z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GIT_URL_BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;GIT_URL_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://www.example.com/git"&lt;/span&gt;
&lt;span class="o"&gt;{&lt;/span&gt;
   &lt;span class="c1"&gt;# fix column name, and then add the dest link&lt;/span&gt;
   sed -r -e &lt;span class="s1"&gt;'1s/web_url/origin/;'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; tr -d &lt;span class="s1"&gt;'"'&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
   awk -v &lt;span class="s2"&gt;"topurl=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GIT_URL_BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; -F&lt;span class="s1"&gt;','&lt;/span&gt; &lt;span class="s1"&gt;'BEGIN{OFS=","} NR==1 {print $0",dest"} NR&amp;gt;1 {$NF=$NF","topurl"/"$1;print}'&lt;/span&gt;
&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;h5&gt;repos.csv&lt;/h5&gt;
&lt;p&gt;The final list asset. Just a snippet:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;ansible01&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;gitlab&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;bgstack15&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;ansible01&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;www&lt;/span&gt;.&lt;span class="nv"&gt;example&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;git&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;ansible01&lt;/span&gt;
&lt;span class="nv"&gt;ansible&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;tunnel&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;proxy&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;gitlab&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;bgstack15&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;ansible&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;tunnel&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;proxy&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;www&lt;/span&gt;.&lt;span class="nv"&gt;example&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;git&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;ansible&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;ssh&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;tunnel&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;proxy&lt;/span&gt;
&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;gitlab&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;www&lt;/span&gt;.&lt;span class="nv"&gt;example&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;git&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;
&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libksba&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;gitlab&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libksba&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;www&lt;/span&gt;.&lt;span class="nv"&gt;example&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;git&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libksba&lt;/span&gt;
&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libassuan&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;gitlab&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libassuan&lt;/span&gt;,&lt;span class="nv"&gt;https&lt;/span&gt;:&lt;span class="o"&gt;//&lt;/span&gt;&lt;span class="nv"&gt;www&lt;/span&gt;.&lt;span class="nv"&gt;example&lt;/span&gt;.&lt;span class="nv"&gt;com&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;git&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;el7&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;gnupg2&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;debmirror&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;libassuan&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h5&gt;make-blank.sh&lt;/h5&gt;
&lt;table class="codehilitetable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;
&lt;span class="normal"&gt;30&lt;/span&gt;
&lt;span class="normal"&gt;31&lt;/span&gt;
&lt;span class="normal"&gt;32&lt;/span&gt;
&lt;span class="normal"&gt;33&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2021-04-17 16:13&lt;/span&gt;
&lt;span class="c1"&gt;# Goal: given the repos.csv output from STEP 2 add-dest.sh script, make the blank git repos for each of those on the final destination server&lt;/span&gt;
&lt;span class="c1"&gt;# STEP 3&lt;/span&gt;

&lt;span class="nb"&gt;test&lt;/span&gt; -z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GIT_URL_BASE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;GIT_URL_BASE&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"https://www.example.com/git"&lt;/span&gt;
&lt;span class="nb"&gt;test&lt;/span&gt; -z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GIT_TOP_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nv"&gt;GIT_TOP_DIR&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"/mnt/public/www/git"&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GIT_TOP_DIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="c1"&gt;# this awk will read stdin, and skip the first line which is the headers for the columns&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; word &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt; awk -F&lt;span class="s1"&gt;','&lt;/span&gt; -v &lt;span class="s2"&gt;"topurl=&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;GIT_URL_BASE&lt;/span&gt;&lt;span class="p"&gt;%%/&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/"&lt;/span&gt; &lt;span class="s1"&gt;'NR&amp;gt;1 {gsub(topurl,"",$3);print $3}'&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="c1"&gt;# if OVERWRITE and the dir already exists, then delete it&lt;/span&gt;
   &lt;span class="nb"&gt;test&lt;/span&gt; -d &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -n &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;OVERWRITE&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; rm -r &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

   &lt;span class="c1"&gt;# If inside a namespace, then perform a few extra steps.&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -qE &lt;span class="s2"&gt;"\/"&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
      &lt;span class="c1"&gt;# make any subdirs between here and there&lt;/span&gt;
      mkdir -p &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="c1"&gt;# DISABLED; can just use section-from-path=1 in main cgitrc&lt;/span&gt;
   &lt;span class="c1"&gt;## if in a subdir, add a cgitrc file for this repo that indicates its section.&lt;/span&gt;
   &lt;span class="c1"&gt;#   section="$( echo "${word}" | awk -F'/' 'BEGIN{OFS="/"} {$NF="";print}' )"&lt;/span&gt;
   &lt;span class="c1"&gt;#   if ! grep -qE "section=.+" "${word}/cgitrc" 2&amp;gt;/dev/null ;&lt;/span&gt;
   &lt;span class="c1"&gt;#   then&lt;/span&gt;
   &lt;span class="c1"&gt;#      echo "section=${section%%/}" &amp;gt;&amp;gt; "${word}/cgitrc"&lt;/span&gt;
   &lt;span class="c1"&gt;#   fi&lt;/span&gt;
   &lt;span class="o"&gt;}&lt;/span&gt;

   &lt;span class="c1"&gt;# actually make the blank git repo&lt;/span&gt;
   git init --bare &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;word&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;

&lt;span class="k"&gt;done&lt;/span&gt;
&lt;span class="nb"&gt;wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;h5&gt;sync-all.sh&lt;/h5&gt;
&lt;table class="codehilitetable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;
&lt;span class="normal"&gt;16&lt;/span&gt;
&lt;span class="normal"&gt;17&lt;/span&gt;
&lt;span class="normal"&gt;18&lt;/span&gt;
&lt;span class="normal"&gt;19&lt;/span&gt;
&lt;span class="normal"&gt;20&lt;/span&gt;
&lt;span class="normal"&gt;21&lt;/span&gt;
&lt;span class="normal"&gt;22&lt;/span&gt;
&lt;span class="normal"&gt;23&lt;/span&gt;
&lt;span class="normal"&gt;24&lt;/span&gt;
&lt;span class="normal"&gt;25&lt;/span&gt;
&lt;span class="normal"&gt;26&lt;/span&gt;
&lt;span class="normal"&gt;27&lt;/span&gt;
&lt;span class="normal"&gt;28&lt;/span&gt;
&lt;span class="normal"&gt;29&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c1"&gt;# STEP 5 repeating&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2020-05-21&lt;/span&gt;
&lt;span class="c1"&gt;# Goal: download every single git repository in full from bitbucket cloud for migration to bitbucket on-prem.&lt;/span&gt;
&lt;span class="c1"&gt;# History:&lt;/span&gt;
&lt;span class="c1"&gt;#    2021-04-17 forked from gituser.tgz to Support/Programs/cgit/populate project&lt;/span&gt;
&lt;span class="c1"&gt;# Usage:&lt;/span&gt;
&lt;span class="c1"&gt;#    INDIR=~/dev/sync-git &lt;/span&gt;
&lt;span class="c1"&gt;# References:&lt;/span&gt;
&lt;span class="c1"&gt;#    git-sync-all.ps1&lt;/span&gt;
&lt;span class="c1"&gt;# Dependencies:&lt;/span&gt;

&lt;span class="nv"&gt;SYNCSCRIPT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/mnt/public/Support/Programs/cgit/populate/sync.sh

&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="nb"&gt;test&lt;/span&gt; -z &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INDIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="o"&gt;||&lt;/span&gt; ! &lt;span class="nb"&gt;test&lt;/span&gt; -r &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INDIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;then&lt;/span&gt;
   &lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;"Fatal! Invalid INDIR &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INDIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; which is either absent or unreadable. Aborted"&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;
   &lt;span class="nb"&gt;exit&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;
&lt;span class="k"&gt;fi&lt;/span&gt;

&lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INDIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; dir &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="k"&gt;$(&lt;/span&gt; find . -maxdepth &lt;span class="m"&gt;2&lt;/span&gt; -mindepth &lt;span class="m"&gt;1&lt;/span&gt; -type d -name &lt;span class="s1"&gt;'.git'&lt;/span&gt; -printf &lt;span class="s1"&gt;'%h\n'&lt;/span&gt; &lt;span class="k"&gt;)&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;do&lt;/span&gt;
   &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="k"&gt;$((&lt;/span&gt; &lt;span class="nv"&gt;x&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;x+1 &lt;span class="k"&gt;))&lt;/span&gt;
   lecho &lt;span class="s2"&gt;"Starting repo &lt;/span&gt;&lt;span class="nv"&gt;$x&lt;/span&gt;&lt;span class="s2"&gt; &lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;INDIR&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;dir&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
   &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;SYNCSCRIPT&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;span class="k"&gt;done&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;h5&gt;sync.sh&lt;/h5&gt;
&lt;table class="codehilitetable"&gt;&lt;tr&gt;&lt;td class="linenos"&gt;&lt;div class="linenodiv"&gt;&lt;pre&gt;&lt;span class="normal"&gt; 1&lt;/span&gt;
&lt;span class="normal"&gt; 2&lt;/span&gt;
&lt;span class="normal"&gt; 3&lt;/span&gt;
&lt;span class="normal"&gt; 4&lt;/span&gt;
&lt;span class="normal"&gt; 5&lt;/span&gt;
&lt;span class="normal"&gt; 6&lt;/span&gt;
&lt;span class="normal"&gt; 7&lt;/span&gt;
&lt;span class="normal"&gt; 8&lt;/span&gt;
&lt;span class="normal"&gt; 9&lt;/span&gt;
&lt;span class="normal"&gt;10&lt;/span&gt;
&lt;span class="normal"&gt;11&lt;/span&gt;
&lt;span class="normal"&gt;12&lt;/span&gt;
&lt;span class="normal"&gt;13&lt;/span&gt;
&lt;span class="normal"&gt;14&lt;/span&gt;
&lt;span class="normal"&gt;15&lt;/span&gt;&lt;/pre&gt;&lt;/div&gt;&lt;/td&gt;&lt;td class="code"&gt;&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="ch"&gt;#!/bin/sh&lt;/span&gt;
&lt;span class="c1"&gt;# STEP 5 or manual&lt;/span&gt;
&lt;span class="c1"&gt;# Startdate: 2020-05-21&lt;/span&gt;
&lt;span class="c1"&gt;# Goal: sync just this one directory git repo.&lt;/span&gt;
&lt;span class="c1"&gt;# History:&lt;/span&gt;
&lt;span class="c1"&gt;#    2021-04-17 forked from gituser.tgz to Supoprt/Programs/cgit/populate project&lt;/span&gt;
&lt;span class="c1"&gt;# References:&lt;/span&gt;
&lt;span class="c1"&gt;#    How to actually pull all branches from the remote https://stackoverflow.com/questions/67699/how-to-clone-all-remote-branches-in-git/16563327#16563327&lt;/span&gt;
&lt;span class="c1"&gt;# Dependencies:&lt;/span&gt;
&lt;span class="c1"&gt;#    $PWD is the git repo in question.&lt;/span&gt;
git pull --all
&lt;span class="o"&gt;{&lt;/span&gt;
   git branch -a &lt;span class="p"&gt;|&lt;/span&gt; sed -n &lt;span class="s2"&gt;"/\/HEAD /d; /remotes\/origin/p;"&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; xargs -L1 git checkout -t
&lt;span class="o"&gt;}&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&amp;gt;&lt;span class="p"&gt;&amp;amp;&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; grep -vE &lt;span class="s1"&gt;'fatal:.* already exists'&lt;/span&gt;
git push dest --all
&lt;/code&gt;&lt;/pre&gt;
&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;</description><category>cgit</category><category>httpd</category><category>selfhosting</category><category>shell</category><guid>https://bgstack15.ddns.net/blog/posts/2021/04/25/populating-my-new-cgit-instance/</guid><pubDate>Sun, 25 Apr 2021 13:15:44 GMT</pubDate></item><item><title>Cgit solution for my network</title><link>https://bgstack15.ddns.net/blog/posts/2021/04/21/cgit-solution-for-my-network/</link><dc:creator>bgstack15</dc:creator><description>&lt;h3&gt;History&lt;/h3&gt;
&lt;p&gt;Experimentation using gitweb and cgit was carried out on d2-02a at some point
before 2020-10. Cgit on Devuan (d2-02a) was examined after investigating a key
&lt;a href="https://stackoverflow.com/questions/26734933/how-to-set-up-git-over-http"&gt;Stackoverflow post&lt;/a&gt; and determined to meet my needs.&lt;/p&gt;
&lt;h3&gt;Overview&lt;/h3&gt;
&lt;p&gt;Git-scm itself provides native mechanisms to allow operations through http,
and basic Apache httpd configuration examples abound. Adding a decent web
frontend with cgit is a small additional step. This setup also uses Apache
httpd basic auth to limit read and write access to the true git projects, but
not the cgit simple http clone operations.&lt;/p&gt;
&lt;h3&gt;Prerequisites&lt;/h3&gt;
&lt;p&gt;Apache httpd is installed. TLS certificate exists and is already in use.&lt;/p&gt;
&lt;h3&gt;Installing entire cgit solution&lt;/h3&gt;
&lt;h4&gt;Installing and configuring cgit&lt;/h4&gt;
&lt;p&gt;Install cgit from stackrpms repo for el8, which uses
&lt;a href="https://src.fedoraproject.org/fork/tmz/rpms/cgit"&gt;https://src.fedoraproject.org/fork/tmz/rpms/cgit&lt;/a&gt; or
&lt;a href="https://src.fedoraproject.org/forks/tmz/rpms/cgit.git"&gt;https://src.fedoraproject.org/forks/tmz/rpms/cgit.git&lt;/a&gt; to build the rpm. Tmz
is the Fedora maintainer of this package, so his adaptation of it for el8 is
trustworthy.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo dnf install cgit
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Modify &lt;code&gt;/etc/cgitrc&lt;/code&gt; with my own customizations. See internal file
/mnt/public/Support/Programs/cgit/files/cgitrc for the original configuration.
Install a few dependencies. Python3-markdown is also from stackrpms for el8,
because I had to build it on my
&lt;a href="https://copr.fedorainfracloud.org/coprs/bgstack15/stackrpms/package/python-markdown/"&gt;copr&lt;/a&gt;, also from its source &lt;a href="https://src.fedoraproject.org/rpms/python-markdown"&gt;https://src.fedoraproject.org/rpms/python-markdown&lt;/a&gt;.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo dnf install python3-pygments python3-markdown
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;These dependencies support displaying markdown (.md) files as the cgit and
repo "about" pages. I tend to use markdown for these types of files. Copy in a
logo file for myself to &lt;code&gt;/usr/share/cgit/bgstack15_64.png&lt;/code&gt;. The top-level
readme file is configured in the example cgitrc to &lt;code&gt;/var/www/git/readme.md&lt;/code&gt;&lt;/p&gt;
&lt;h4&gt;Configuring httpd&lt;/h4&gt;
&lt;p&gt;Set up file &lt;code&gt;/etc/git_access.conf&lt;/code&gt; with snippets that will be included by the
httpd config. This file will control access to the git repositories over git
itself, not the cgit web presentation.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;# &lt;span class="nv"&gt;File&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;etc&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;git_access&lt;/span&gt;.&lt;span class="nv"&gt;conf&lt;/span&gt;
# &lt;span class="nv"&gt;Part&lt;/span&gt; &lt;span class="nv"&gt;of&lt;/span&gt; &lt;span class="nv"&gt;cgit&lt;/span&gt; &lt;span class="nv"&gt;solution&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nv"&gt;Mersey&lt;/span&gt; &lt;span class="nv"&gt;network&lt;/span&gt;, &lt;span class="mi"&gt;2021&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;04&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mi"&gt;15&lt;/span&gt;
# &lt;span class="nv"&gt;The&lt;/span&gt; &lt;span class="nv"&gt;last&lt;/span&gt; &lt;span class="nv"&gt;phrase&lt;/span&gt; &lt;span class="nv"&gt;can&lt;/span&gt; &lt;span class="nv"&gt;be&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all granted&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;allow&lt;/span&gt; &lt;span class="nv"&gt;anybody&lt;/span&gt; &lt;span class="nv"&gt;to&lt;/span&gt; &lt;span class="nv"&gt;read&lt;/span&gt;.
# &lt;span class="nv"&gt;Use&lt;/span&gt; &lt;span class="nv"&gt;httpd&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Require&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nv"&gt;strings&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="nb"&gt;param2&lt;/span&gt;, &lt;span class="nb"&gt;param3&lt;/span&gt;. &lt;span class="nb"&gt;Param2&lt;/span&gt; &lt;span class="nv"&gt;grants&lt;/span&gt; &lt;span class="nv"&gt;read&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nv"&gt;write&lt;/span&gt; &lt;span class="nv"&gt;permission&lt;/span&gt;, &lt;span class="nb"&gt;Param3&lt;/span&gt; &lt;span class="nv"&gt;is&lt;/span&gt; &lt;span class="nv"&gt;read&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;only&lt;/span&gt;.
#&lt;span class="nv"&gt;Use&lt;/span&gt; &lt;span class="nv"&gt;Project&lt;/span&gt; &lt;span class="k"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user alice bob charlie&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all granted&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
#&lt;span class="nv"&gt;Use&lt;/span&gt; &lt;span class="nv"&gt;Project&lt;/span&gt; &lt;span class="k"&gt;dirname&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user charlie&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user bob alice&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;

&lt;span class="nv"&gt;Use&lt;/span&gt; &lt;span class="nv"&gt;Project&lt;/span&gt; &lt;span class="nv"&gt;certreq&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;user bgstack15&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="s"&gt;all granted&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;In the above example, the "certreq" is a project name (directory name under
/var/www/git). The second and third parameters, the "user bgstack15" and "all
granted" will be passed to Apache "Require" directives. They represent "read-
write access" and "read-only access" respectively. Apache interprets the
example, resolved "Required all granted" as anonymous read access is allowed.
One of the main operations described under the Operations heading below is
adding new entries to this list of projects. Set up file &lt;code&gt;/etc/gitweb.conf&lt;/code&gt;
which is traditionally for gitweb, a different implementation of serving git
repos over http, but can also be used here.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;$export_auth_hook&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;sub&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$repo&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;shift&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$user&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$cgi&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;remote_user&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$repo&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/\/var\/www\/git\///&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nb"&gt;open&lt;/span&gt; &lt;span class="n"&gt;FILE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;'/etc/git_access.conf'&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; 
        &lt;span class="k"&gt;while&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sr"&gt;&amp;lt;FILE&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nv"&gt;$_&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;m/Use Project $repo \"(.*)\" \"(.*)\"/&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;my&lt;/span&gt; &lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nv"&gt;$1&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="s"&gt;' '&lt;/span&gt; &lt;span class="o"&gt;.&lt;/span&gt; &lt;span class="nv"&gt;$2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/all granted/$user/&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;s/user//&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt; &lt;span class="nv"&gt;$users&lt;/span&gt; &lt;span class="o"&gt;=~&lt;/span&gt; &lt;span class="sr"&gt;m/$user/&lt;/span&gt; &lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;              
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;I do not understand this perl file: It came straight from &lt;a href="https://stackoverflow.com/a/50317063/3569534"&gt;reference
2&lt;/a&gt;. Set up file
&lt;code&gt;/etc/git_access&lt;/code&gt; with htpasswd(1).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;sudo htpasswd -c /etc/git_access bgstack15
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Set up file &lt;code&gt;/etc/httpd/conf.d/cgit.conf&lt;/code&gt; with modifications. This file is
laid down by the cgit rpm, but might need some adjustments. The exact contents
as of the time of this writing are the following.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Alias /cgit-data /usr/share/cgit
ScriptAlias /cgit /var/www/cgi-bin/cgit
RedirectMatch ^/cgit$ /git/
&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt; &lt;span class="err"&gt;"/usr/share/cgit/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    AllowOverride None
    Require all granted
&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Set up the apache virtualhost. For server storage1, this means modifying
extant file &lt;code&gt;/etc/httpd/conf.d/local_mirror.conf&lt;/code&gt;. Inside the main VirtualHost
definition (the port 80 one), add contents:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;# cgit + git. See /mnt/public/Support/Programs/cgit/cgit-README.md
SetEnv GIT_PROJECT_ROOT /var/www/git
SetEnv GIT_HTTP_EXPORT_ALL
SetEnv REMOTE_USER=$REDIRECT_REMOTE_USER
SetEnv GITWEB_CONFIG /etc/gitweb.conf

ScriptAlias /git/ /usr/libexec/git-core/git-http-backend/
&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt; &lt;span class="err"&gt;"/usr/libexec/git-core*"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    Options +ExecCGI +Indexes
    Order allow,deny
    Allow from all
    Require all granted
&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;

# a2enmod macro # for Devuan
&lt;span class="nt"&gt;&amp;lt;Macro&lt;/span&gt; &lt;span class="err"&gt;Project&lt;/span&gt; &lt;span class="err"&gt;$repository&lt;/span&gt; &lt;span class="err"&gt;$rwstring&lt;/span&gt; &lt;span class="err"&gt;$rostring&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LocationMatch&lt;/span&gt; &lt;span class="err"&gt;"^/git/$repository.*$"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        AuthType Basic
        AuthName "Git Access"
        AuthUserFile /etc/git_access
        Require $rwstring
        Require $rostring
    &lt;span class="nt"&gt;&amp;lt;/LocationMatch&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;LocationMatch&lt;/span&gt; &lt;span class="err"&gt;"^/git/$repository/git-receive-pack$"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        AuthType Basic
        AuthName "Git Access"
        AuthUserFile /etc/git_access
        Require $rwstring
    &lt;span class="nt"&gt;&amp;lt;/LocationMatch&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Macro&amp;gt;&lt;/span&gt;
# Devuan apache2 works with IncludeOptional but EL8 httpd doesn't work with it.
Include /etc/git_access.conf

# https://ic3man5.wordpress.com/2013/01/26/installing-cgit-on-debian/
# depends on conf-enabled/cgit.conf (available as cgit.conf.devuan)
&lt;span class="nt"&gt;&amp;lt;Directory&lt;/span&gt; &lt;span class="err"&gt;"/usr/share/cgit/"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    SetEnv CGIT_CONFIG /etc/cgitrc
    SetEnv GIT_URL cgit
    AllowOverride all
    Options +ExecCGI +FollowSymLinks +Indexes
    DirectoryIndex cgit.cgi
    AddHandler cgi-script .cgi
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    RewriteRule (.*) /cgit/cgit.cgi/$1 [END,QSA]
&lt;span class="nt"&gt;&amp;lt;/Directory&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After making changes to these files, test (sudo httpd -t), and then reload or
restart httpd.&lt;/p&gt;
&lt;h3&gt;Configure SELinux&lt;/h3&gt;
&lt;p&gt;I used the standard mechanisms to troubleshoot SELinux.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;setenforce&lt;/span&gt; &lt;span class="mi"&gt;0&lt;/span&gt;
&lt;span class="n"&gt;semodule&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;disable_dontaudit&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;
&lt;span class="n"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;""&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;tee&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;audit&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;audit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;/&lt;/span&gt;&lt;span class="n"&gt;dev&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb nb-Type"&gt;null&lt;/span&gt;
&lt;span class="c1"&gt;# perform a large number of git and cgit operations&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;tail&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n15000&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="nb"&gt;log&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;audit&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;audit&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="o"&gt;|&lt;/span&gt; &lt;span class="n"&gt;audit2allow&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="n"&gt;foo&lt;/span&gt;
&lt;span class="c1"&gt;# manually merge any new entries into cgitmersey.te&lt;/span&gt;
&lt;span class="n"&gt;semodule&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;build&lt;/span&gt;
&lt;span class="n"&gt;_func&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;checkmodule&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;cgitmersey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="n"&gt;cgitmersey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;te&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;semodule_package&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;o&lt;/span&gt; &lt;span class="n"&gt;cgitmersey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;m&lt;/span&gt; &lt;span class="n"&gt;cgitmersey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;mod&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;semodule&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="n"&gt;cgitmersey&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;pp&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;time&lt;/span&gt; &lt;span class="n"&gt;_func&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Final asset is &lt;code&gt;cgitmersey.te&lt;/code&gt; which can be loaded and installed with the last
line of the above command block.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;module&lt;/span&gt; &lt;span class="n"&gt;cgitmersey&lt;/span&gt; &lt;span class="mf"&gt;1.0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;require&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;git_script_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;httpd_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;httpd_cache_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="n"&gt;var_t&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noatsecure&lt;/span&gt; &lt;span class="n"&gt;rlimitinh&lt;/span&gt; &lt;span class="n"&gt;siginh&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;getattr&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;getattr&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;#============= git_script_t ==============&lt;/span&gt;
&lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="n"&gt;git_script_t&lt;/span&gt; &lt;span class="n"&gt;var_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="n"&gt;git_script_t&lt;/span&gt; &lt;span class="n"&gt;var_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="n"&gt;getattr&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="n"&gt;git_script_t&lt;/span&gt; &lt;span class="n"&gt;httpd_cache_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;dir&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;getattr&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="n"&gt;search&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="n"&gt;git_script_t&lt;/span&gt; &lt;span class="n"&gt;httpd_cache_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;file&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;map&lt;/span&gt; &lt;span class="n"&gt;getattr&lt;/span&gt; &lt;span class="n"&gt;open&lt;/span&gt; &lt;span class="n"&gt;read&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;#============= httpd_t ==============&lt;/span&gt;
&lt;span class="n"&gt;allow&lt;/span&gt; &lt;span class="n"&gt;httpd_t&lt;/span&gt; &lt;span class="n"&gt;git_script_t&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;process&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;noatsecure&lt;/span&gt; &lt;span class="n"&gt;rlimitinh&lt;/span&gt; &lt;span class="n"&gt;siginh&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h3&gt;Populating cgit with my content&lt;/h3&gt;
&lt;p&gt;See separate blog post &lt;a href="https://bgstack15.ddns.net/blog/posts/2021/04/25/populating-my-new-cgit-instance/"&gt;Populating my New Cgit
Instance&lt;/a&gt; for this whole task.&lt;/p&gt;
&lt;h3&gt;Summary of associated files&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;/etc/gitweb.conf&lt;/li&gt;
&lt;li&gt;/usr/share/cgit/bgstack15_64.png&lt;/li&gt;
&lt;li&gt;/etc/git_access.conf&lt;/li&gt;
&lt;li&gt;/etc/git_access&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;/etc/cgitrc &lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;cache-size=300
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;clone-prefix=https://www.example.com/git
css=/cgit-data/cgit.css&lt;/p&gt;
&lt;h2&gt;Disable owner on index page&lt;/h2&gt;
&lt;p&gt;enable-index-owner=0
enable-index-links=1&lt;/p&gt;
&lt;h2&gt;Allow http transport git clone&lt;/h2&gt;
&lt;p&gt;enable-http-clone=1&lt;/p&gt;
&lt;h2&gt;Show extra links for each repository on the index page&lt;/h2&gt;
&lt;h2&gt;enable-index-links=0&lt;/h2&gt;
&lt;h2&gt;Enable blame page and create links to it from tree page&lt;/h2&gt;
&lt;h2&gt;enable-blame=0&lt;/h2&gt;
&lt;h2&gt;Enable ASCII art commit history graph on the log pages&lt;/h2&gt;
&lt;h2&gt;enable-commit-graph=0&lt;/h2&gt;
&lt;h2&gt;Show number of affected files per commit on the log pages&lt;/h2&gt;
&lt;h2&gt;enable-log-filecount=0&lt;/h2&gt;
&lt;h2&gt;Show number of added/removed lines per commit on the log pages&lt;/h2&gt;
&lt;h2&gt;enable-log-linecount=0&lt;/h2&gt;
&lt;h2&gt;Sort branches by age or name&lt;/h2&gt;
&lt;h2&gt;branch-sort=name&lt;/h2&gt;
&lt;h2&gt;favicon=/favicon.ico&lt;/h2&gt;
&lt;h2&gt;Use a custom logo&lt;/h2&gt;
&lt;p&gt;logo=/cgit-data/bgstack15_64.png&lt;/p&gt;
&lt;h2&gt;Enable statistics per week, month, quarter, or year&lt;/h2&gt;
&lt;h2&gt;max-stats=&lt;/h2&gt;
&lt;h2&gt;Set the title and heading of the repository index page&lt;/h2&gt;
&lt;p&gt;root-title=Stackrpms git
root-readme=/var/www/git/readme.md
root-desc=Bgstack15 local repos&lt;/p&gt;
&lt;h2&gt;Allow download of tar.gz, tar.bz2 and zip-files&lt;/h2&gt;
&lt;p&gt;snapshots=tar.gz tar.bz2 zip
mimetype.gif=image/gif
mimetype.html=text/html
mimetype.jpg=image/jpeg
mimetype.jpeg=image/jpeg
mimetype.pdf=application/pdf
mimetype.png=image/png
mimetype.svg=image/svg+xml&lt;/p&gt;
&lt;h2&gt;Enable syntax highlighting (requires the highlight package)&lt;/h2&gt;
&lt;p&gt;source-filter=/usr/libexec/cgit/filters/syntax-highlighting.sh&lt;/p&gt;
&lt;h2&gt;Format markdown, restructuredtext, manpages, text files, and html files&lt;/h2&gt;
&lt;h2&gt;through the right converters&lt;/h2&gt;
&lt;p&gt;about-filter=/usr/libexec/cgit/filters/about-formatting.sh
readme=:README.md
readme=:readme.md
readme=:README.mkd
readme=:readme.mkd
readme=:README.rst
readme=:readme.rst
readme=:README.html
readme=:readme.html
readme=:README.htm
readme=:readme.htm
readme=:README.txt
readme=:readme.txt
readme=:README
readme=:readme
readme=:INSTALL.md
readme=:install.md
readme=:INSTALL.mkd
readme=:install.mkd
readme=:INSTALL.rst
readme=:install.rst
readme=:INSTALL.html
readme=:install.html
readme=:INSTALL.htm
readme=:install.htm
readme=:INSTALL.txt
readme=:install.txt
readme=:INSTALL
readme=:install
section-from-path=1
enable-subject-links=1
virtual-root=/cgit/
scan-path=/var/www/git/&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;/etc/httpd/conf.d/cgit.conf&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;/var/www/git/readme.md&lt;/li&gt;
&lt;li&gt;/mnt/public/Support/Programs/cgit/cgitmersey.te&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Operations&lt;/h3&gt;
&lt;p&gt;Some useful operations are described here.&lt;/p&gt;
&lt;h4&gt;Making a new project&lt;/h4&gt;
&lt;p&gt;To set up a new project that can receive pushes, you need to initialize a new
git bare repo. Make the "newname" project in /var/www/git, and grant access to
the apache user.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;cd&lt;/span&gt; &lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="k"&gt;var&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;www&lt;/span&gt;&lt;span class="o"&gt;/&lt;/span&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;init&lt;/span&gt; &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;bare&lt;/span&gt; &lt;span class="n"&gt;newname&lt;/span&gt; &lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;chgrp&lt;/span&gt; &lt;span class="n"&gt;apache&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;R&lt;/span&gt; &lt;span class="n"&gt;newname&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;Set up permissions for the new project in &lt;code&gt;/etc/git_access.conf&lt;/code&gt;. For example:&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;Use Project "newname" "user adminuser1 adminuser2 adminuser3" "user1 user2 user3"
&lt;/code&gt;&lt;/pre&gt;

&lt;p&gt;After making changes, ensure httpd accepts the new config (because it loads
/etc/git_access.conf as an included file), and then reload httpd.&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;httpd&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;t&lt;/span&gt;
&lt;span class="n"&gt;sudo&lt;/span&gt; &lt;span class="n"&gt;systemctl&lt;/span&gt; &lt;span class="n"&gt;reload&lt;/span&gt; &lt;span class="n"&gt;httpd&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Changing cgit-related attributes of a project&lt;/h4&gt;
&lt;p&gt;Cgit can be configured to read a file named &lt;code&gt;cgitrc&lt;/code&gt; within a git repository.
I tend to use just the top directory of these bare git repos, so for project
certreq, use &lt;code&gt;/var/www/git/certreq/cgitrc&lt;/code&gt;. See cgitrc(5) for more info, but a
brief list of useful attributes (var=value) include: defbranch, desc, hide,
homepage, ignore, logo, name, owner, readme, section, url. For the description
of a repo that appears in the main index, use regular file in a git bare repo:
&lt;code&gt;description&lt;/code&gt;.&lt;/p&gt;
&lt;h4&gt;Adding a new user&lt;/h4&gt;
&lt;p&gt;Use regular htpasswd mechanism to add users or change passwords. See
htpasswd(1).&lt;/p&gt;
&lt;pre class="code literal-block"&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;htpasswd /etc/git_access bgstack15
&lt;/code&gt;&lt;/pre&gt;

&lt;h4&gt;Removing a project&lt;/h4&gt;
&lt;p&gt;Just delete the project directory.&lt;/p&gt;
&lt;h4&gt;Changing cgitrc values&lt;/h4&gt;
&lt;p&gt;Changing cgitrc values take effect immediately (when caching is set to 0); no
httpd reload is necessary.&lt;/p&gt;
&lt;h3&gt;References&lt;/h3&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/26734933/how-to-set-up-git-over-http"&gt;https://stackoverflow.com/questions/26734933/how-to-set-up-git-over-http&lt;/a&gt; git_access.conf&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/a/50317063/3569534"&gt;https://stackoverflow.com/a/50317063/3569534&lt;/a&gt; /etc/gitweb.conf and httpd.conf macro and other snippets&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/questions/40924641/setting-up-git-http-backend-with-apache-2-4"&gt;https://stackoverflow.com/questions/40924641/setting-up-git-http-backend-with-apache-2-4&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://stackoverflow.com/a/2200662/3569534"&gt;https://stackoverflow.com/a/2200662/3569534&lt;/a&gt; had to convert my sample project to a bare git one&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Auxiliary reading&lt;/h4&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://ic3man5.wordpress.com/2013/01/26/installing-cgit-on-debian/"&gt;https://ic3man5.wordpress.com/2013/01/26/installing-cgit-on-debian/&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;
&lt;h4&gt;Alternatives&lt;/h4&gt;
&lt;h6&gt;added 2022-01-18&lt;/h6&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://shreyasminocha.me/blog/replacing-gitea/"&gt;Shreyas Minocha's Replacing Gitea&lt;/a&gt;&lt;/li&gt;
&lt;/ol&gt;</description><category>cgit</category><category>git</category><category>httpd</category><category>selfhosting</category><category>selinux</category><guid>https://bgstack15.ddns.net/blog/posts/2021/04/21/cgit-solution-for-my-network/</guid><pubDate>Wed, 21 Apr 2021 12:36:21 GMT</pubDate></item></channel></rss>