Setting up a Website with Cgit on Fedora 34

Date: May 9, 2021

Last Updated: Nov 13, 2022

In this short post, I'm going to write down the instructions I used to set up a simple website to host my git repositories using cgit on Fedora 34.

The first thing to do is to copy over an ssh key and disable remote login with a password. Assuming you already have an ssh key you can just run:

$ ssh-copy-id -i ~/.ssh/id_rsa.pub root@[remote ip]

where [remote ip] is the ip address of the machine you want to host things on. After doing so you can log onto the remote machine and edit /etc/ssh/sshd_config and update the following line to

PasswordAuthentication no

and then restart sshd:

# systemctl restart sshd

Next, it's always a good idea to update everything on the remote machine:

# yum update

Next, we need to install the web server and cgit

# yum install git, cgit, httpd

Now, you can copy over your website's index.html and any other files to /var/www/html.

Iptables Rules

By default, Fedora 34 uses firewalld to create a firewall. I prefer to use the simpler method of directly editing iptables, so I disabled firewalld:

# systemctl stop firewalld
# systemctl disable firewalld
# systemctl mask firewalld

Next, install iptables-services and activate it:

# yum install iptables-services
# systemctl enable iptables.service
# systemctl enable ip6tables.service

Next, I edited the iptables rules to only allow ssh and web traffic:

# iptables -A INPUT -o lo -j ACCEPT
# iptables -A INPUT -p tcp --dport 22 -j ACCEPT
# iptables -A INPUT -p tcp --dport 80 -j ACCEPT
# iptables -A INPUT -p tcp --dport 443 -j ACCEPT
# iptables -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
# iptables -P INPUT DROP
# iptables -P FORWARD DROP

After doing so, your iptables should look like:

# iptables --list
Chain INPUT (policy DROP)
target     prot opt source               destination         
ACCEPT     all  --  anywhere             anywhere            
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:ssh
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:http
ACCEPT     tcp  --  anywhere             anywhere             tcp dpt:https
ACCEPT     all  --  anywhere             anywhere             state RELATED,ESTABLISHED

Chain FORWARD (policy DROP)
target     prot opt source               destination         

Chain OUTPUT (policy ACCEPT)
target     prot opt source               destination         

Now, we have to save our new rules or they will get lost in a reboot:

# iptables-save > /etc/sysconfig/iptables

Next, we'll copy over these rules for IPv6:

# ip6tables-restore /etc/sysconfig/iptables
# ip6tables-save > /etc/sysconfig/ip6tables

Note: Reading online it seems that for IPv6 to work, it's critical to enable ICMP packets. Since I'm not setting things up on IPv6, I've ignored this, but it might be worth adding a rule to the ip6tables rules for these packets as suggested here .

After completing the above steps, I still couldn't get the cgit website to show up at http://www.tlatorre.com/cgit , and I was getting error messages in /var/log/httpd/error_log that looked like:

[timestamp] [cgid:error] [pid 18921:tid 19123] [client foo] fatal: unable to access '/var/lib/git/cgit.git/config': Permission denied: /var/www/cgi-bin/cgit, referer: http://www.tlatorre.com/cgit
[timestamp] [cgid:error] [pid 18921:tid 19123] [client foo] End of script output before headers: cgit, referer: http://www.tlatorre.com/cgit

I think to fix this I had to run:

# setsebool -P httpd_enable_cgi 1

and then restart the apache server

# service httpd restart

but I actually ended up tweaking lots of things and then noticed that it eventually worked, so I'm not 100% sure that is what fixed it.

Update: I tried this on a new machine and it didn't work. I had to run:

# restorecon -vR /var/lib/git/

at some point.

Setting up cgit

To set up cgit, you should edit the file /etc/httpd/conf.d/cgit.conf to look like:

Alias /cgit-data /usr/share/cgit
ScriptAlias /cgit /var/www/cgi-bin/cgit
<Directory "/usr/share/cgit">
    Require all granted
</Directory>

Then, create the directory /var/lib/git and initialize a new empty repository:

# mkdir -p /var/lib/git
# cd /var/lib/git
# mkdir repo.git
# cd repo.git
# git init --bare

Now, from your local machine you can add it as a remote and push the master branch:

$ git remote add web root@[remote ip]:/var/lib/git/repo.git
$ git push web master

Finally, you can edit /etc/cgitrc to add the new repo. Near the bottom of the file you can find some example repositories. Here is what mine looks like for chroma:

repo.url=chroma
repo.path=/var/lib/git/chroma.git
repo.desc=Chroma is a high performance optical photon simulation for particle physics detectors
repo.owner=Anthony LaTorre
repo.readme=chroma/index.html

Next, I uncommented the line

# Allow http transport git clone
enable-http-clone=1

and added the line

# Specify some default clone prefixes
clone-prefix=https://www.tlatorre.com/cgit

so people can clone my repos over https.

Setting up SSL

To set up SSL I mostly followed the instructions at https://tecadmin.net/setup-lets-encrypt-ssl-with-apache-on-fedora/ . First, we need to install the SSL mod for apache and the certbot client:

# yum install python3-certbot-apache mod_ssl

Next, create a new file at /etc/http/conf.d/webhost.example.com.conf which looks like:

<VirtualHost *:80>
    ServerAdmin admin@example.com
    ServerName www.example.com
    DocumentRoot /var/www/html
    <Directory /var/www/html>
        Allowoverride all
    </Directory>
</VirtualHost>

Then run:

# certbot-3 apache

Then, we can check that we can auto renew by running:

# certbot-3 renew --dry-run

and if everything goes well you can run crontab -e and add a rule:

0 * * * * certbot-3 renew

Enabling gzip compression

Create a new file /etc/httpd/conf.d/deflate.conf:

<IfModule mod_deflate.c>
AddOutputFilterByType DEFLATE application/javascript
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/vnd.ms-fontobject
AddOutputFilterByType DEFLATE application/x-font
AddOutputFilterByType DEFLATE application/x-font-opentype
AddOutputFilterByType DEFLATE application/x-font-otf
AddOutputFilterByType DEFLATE application/x-font-truetype
AddOutputFilterByType DEFLATE application/x-font-ttf
AddOutputFilterByType DEFLATE application/x-javascript
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE font/opentype
AddOutputFilterByType DEFLATE font/otf
AddOutputFilterByType DEFLATE font/ttf
AddOutputFilterByType DEFLATE image/svg+xml
AddOutputFilterByType DEFLATE image/x-icon
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/javascript
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/xml
</IfModule>

Then, restart apache:

$ systemctl restart httpd.service

Setting up Automatic Updates with Email Alerts

First, if you're using a linode instance, you need to open a support ticket to make sure that they open ports 587 for you, since they are by default blocked .

Next, we'll install dnf automatic:

$ dnf install dnf-automatic
$ systemctl enable --now dnf-automatic.timer

Now, we need to install something to send email:

$ dnf install msmtp

And now edit ~/.msmtprc to look something like this:

defaults
port 587
tls on
account namecheap
host [email host]
from [email address]
user [email address]
password [password]
account default : namecheap

Now, you can test if it's working:

$ echo "Hello world" | msmtp [your email address]

If so, next edit /etc/dnf/automatic.conf to make sure it includes lines like the following:

apply_updates = yes
emit_via = stdio, command_email
[command_email]
command_format = "msmtp {email_to}"
stdin_format = "Subject: {subject}\n\n{body}"
email_from = [email address]
email_to = [your email address]

That's it!