initial import
BIN
assets/diras/diras-rune-114-263820.png
Normal file
|
After Width: | Height: | Size: 3.2 KiB |
BIN
assets/diras/diras-rune-120-263820.png
Normal file
|
After Width: | Height: | Size: 3.1 KiB |
BIN
assets/diras/diras-rune-144-263820.png
Normal file
|
After Width: | Height: | Size: 3.5 KiB |
BIN
assets/diras/diras-rune-152-263820.png
Normal file
|
After Width: | Height: | Size: 3 KiB |
BIN
assets/diras/diras-rune-16-263820.png
Normal file
|
After Width: | Height: | Size: 357 B |
BIN
assets/diras/diras-rune-24-263820.png
Normal file
|
After Width: | Height: | Size: 578 B |
BIN
assets/diras/diras-rune-32-263820.png
Normal file
|
After Width: | Height: | Size: 813 B |
BIN
assets/diras/diras-rune-48-263820.png
Normal file
|
After Width: | Height: | Size: 1.3 KiB |
BIN
assets/diras/diras-rune-512-263820.png
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
assets/diras/diras-rune-57-263820.png
Normal file
|
After Width: | Height: | Size: 1.6 KiB |
BIN
assets/diras/diras-rune-64-263820.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
assets/diras/diras-rune-72-263820.png
Normal file
|
After Width: | Height: | Size: 1.8 KiB |
BIN
assets/diras/favicon.ico
Normal file
|
After Width: | Height: | Size: 31 KiB |
26
assets/diras/readme.txt
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
Thank you for downloading a favicon from Free Favicon! This favicon was created from an image at http://openclipart.org/ and converted to a favicon and other sizes for you to use in your projects. For more details about this image visit this page: https://openclipart.org/detail/263820/Diras%20Rune
|
||||
|
||||
For more infomation about how you can use this image from OpenClipArt see this page: http://openclipart.org/may-clipart-be-used-comparison
|
||||
|
||||
Here are the contents of this compressed package:
|
||||
|
||||
* favicon.ico -- The favicon file (supports both 16*16 and 32*32 dimensions). You will need to rename this to favicon.ico and upload to your web site.
|
||||
|
||||
* You can add a favicon to your web page by uploading favicon.ico to Root of your website and inserting the following HTML tag between the <head> ... </head> tags of your web page.
|
||||
|
||||
<link rel="shortcut icon" href="favicon.ico" />
|
||||
|
||||
* There are many different sized png files for use a icons for smartphones, tablets and desktop use.
|
||||
|
||||
If you are having any problems installing your favicon we have tips on the Free Favicon blog. http://www.freefavicon.com/blog/
|
||||
|
||||
Thank you once again for download from Free Favicon! If you like your favicon we appreciate you taking the time to mention our service to others, blogging about us and of course by linking to us.
|
||||
|
||||
We also encourage you to check out Backblaze online backup. We use Backblaze to backup our computers and keep our data safe. They offer a free 15 day trial and are the easiest online backup service we have used.
|
||||
|
||||
Use this link http://www.freefavicon.com/blog/outgoing/backblaze.php to try Backblaze for Free!
|
||||
|
||||
By signing up for Backblaze you help keep Free Favicon free!
|
||||
|
||||
Thank you,
|
||||
FreeFavicon.com
|
||||
26
bin/jailstat.sh
Executable file
|
|
@ -0,0 +1,26 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Get list of fail2ban jails and print status of each
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
# fail2ban-client requires root
|
||||
if [[ $(id -u) -ne 0 ]]; then
|
||||
echo "Must run as root user"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
## there's a tab after "list:"
|
||||
## fail2ban-client status ->
|
||||
# Status
|
||||
# |- Number of jail: 3
|
||||
# `- Jail list: nginx-4xx, nginx-limit-req, sshd
|
||||
|
||||
JAILS=$(fail2ban-client status | \
|
||||
awk -F: '/list/{gsub(/, /," ",$2);gsub(/^[ \t]+/,"",$2);print $2}'
|
||||
)
|
||||
|
||||
for jail in ${JAILS}; do
|
||||
fail2ban-client status "${jail}"
|
||||
done
|
||||
|
||||
67
bin/teabak.sh
Executable file
|
|
@ -0,0 +1,67 @@
|
|||
#!/usr/bin/env bash
|
||||
#
|
||||
# Create Gitea backups
|
||||
#
|
||||
# Prep
|
||||
# groupadd --system bkp
|
||||
# mkdir /var/xyzzy/backup
|
||||
# chmod 0750 /var/xyzzy/backup
|
||||
# chown git:bkp /var/xyzzy/backup
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
_VERSION="0.0.2"
|
||||
|
||||
BDTS=$(date +"%Y%m%d%H%M")
|
||||
BDIR="/var/xyzzy/backup"
|
||||
BFILE="${BDIR}/gitea-${BDTS}"
|
||||
|
||||
# gitea dump adds ".tar.xz" to the name dynamically
|
||||
BDMP="${BDIR}/gitea-${BDTS}.tar.xz"
|
||||
BGRP="bkp"
|
||||
|
||||
GCNF="/var/xyzzy/etc/gitea/app.ini"
|
||||
GBIN="/var/xyzzy/bin/gitea"
|
||||
GDATA="/var/xyzzy/gitea"
|
||||
|
||||
# healthchecks.io ping URL upon success, uses curl - "none" to disable
|
||||
HCPING="none"
|
||||
|
||||
# delete backups older than
|
||||
# see 'man find'; "+3" = 3*24h ago
|
||||
BDEL="-mtime +3"
|
||||
|
||||
# we need to chgrp/chmod to a foreign group
|
||||
if [[ $(id -u) -ne 0 ]]; then
|
||||
echo "Must run as root user"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# just to be sure
|
||||
cd "${BDIR}" || (echo "Cannot cd to ${BDIR}"; exit 1)
|
||||
|
||||
# runuser exits with the error code of the command
|
||||
_EC=1
|
||||
runuser -u git -- "${GBIN}" dump --config "${GCNF}" --tempdir "${BDIR}" \
|
||||
--work-path "${GDATA}" --skip-log --type tar.xz --file "${BFILE}"
|
||||
_EC=$?
|
||||
|
||||
# post processing
|
||||
if [[ $_EC -eq 0 ]]; then
|
||||
# gitea dump writes git:git 0600
|
||||
if [[ -f "${BDMP}" ]]; then
|
||||
chgrp "${BGRP}" "${BDMP}"
|
||||
chmod 0640 "${BDMP}"
|
||||
fi
|
||||
# delete older than BDEL backups
|
||||
# shellcheck disable=SC2086
|
||||
find "${BDIR}" -type f ${BDEL} \
|
||||
-regextype egrep \
|
||||
-regex '.*/gitea-[0-9]{12}\.tar\.xz' \
|
||||
-delete
|
||||
# ping healthchecks.io
|
||||
if [[ "${HCPING}" != "none" ]]; then
|
||||
curl -fsS -m 10 --retry 5 -o /dev/null "${HCPING}"
|
||||
fi
|
||||
fi
|
||||
|
||||
144
bin/teaup.sh
Executable file
|
|
@ -0,0 +1,144 @@
|
|||
#!/usr/bin/env bash
|
||||
# shellcheck disable=SC2164,SC2181
|
||||
#
|
||||
# Upgrade gitea binary
|
||||
# - run this under sudo as it replaces and restarts gitea
|
||||
# - "gitea" is a symlink to the numbered github download binary
|
||||
# - allows for quick rollback if needed
|
||||
# - e.g.: 'ln -s gitea-1.16.3-linux-amd64 gitea'
|
||||
#
|
||||
# Exit codes
|
||||
# 0 = Success (already newest or upgrade worked)
|
||||
# 1 = curl failed to download new version
|
||||
# 2 = sha256sum check failed on download
|
||||
# 3 = "gitea" wasn't a symlink
|
||||
# 4 = upgrade version check failed, gitea not restarted
|
||||
# 5 = could not change directory to run sha256sum
|
||||
# 6 = cannot determine Gitea version info
|
||||
# 20 = not running under sudo (see TEA_SUDO)
|
||||
# 21 = gitea upgraded but not restarted (see TEA_HUP)
|
||||
# 22 = gitea upgrade downloaded only (see TEA_LINK)
|
||||
#
|
||||
# Requires: curl, awk, grep, sha256sum
|
||||
# Debug: bash -x /path/to/script.sh
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
_VERSION="0.0.1"
|
||||
|
||||
# symlink name used to run gitea (e.g. "gitea")
|
||||
TEA_SYM="gitea"
|
||||
# where the binary is located (e.g. "/usr/local/bin")
|
||||
TEA_DIR="/var/xyzzy/bin"
|
||||
# 0 = verbose status, 1 = silent and rely on exit codes
|
||||
TEA_QUIET=0
|
||||
|
||||
# require running this script under sudo, 0 to disable
|
||||
TEA_SUDO=1
|
||||
# restart gitea using TEA_CMD, 0 to disable
|
||||
TEA_HUP=0
|
||||
# replace symlink, 0 to disable (download only, implies TEA_HUP=0)
|
||||
TEA_LINK=1
|
||||
# command to restart gitea (e.g. "systemctl restart gitea")
|
||||
TEA_CMD="systemctl restart gitea"
|
||||
|
||||
# github API endpoint to get latest version
|
||||
TEA_API="https://api.github.com/repos/go-gitea/gitea/releases/latest"
|
||||
# github download base URL to prepend with version info
|
||||
TEA_DLB="https://github.com/go-gitea/gitea/releases/download"
|
||||
# architecture being used, matches download name
|
||||
TEA_ARCH="linux-amd64"
|
||||
|
||||
function noise() {
|
||||
if [[ ${TEA_QUIET} -eq 0 ]]; then
|
||||
echo "$*"
|
||||
fi
|
||||
}
|
||||
|
||||
if [[ ${TEA_SUDO} -eq 1 ]]; then
|
||||
if [[ $(id -u) -ne 0 ]]; then
|
||||
noise "Run this script as root (sudo)"
|
||||
exit 20
|
||||
fi
|
||||
fi
|
||||
|
||||
# disable curl download progress if in quiet mode
|
||||
_COPT=""
|
||||
if [[ ${TEA_QUIET} -eq 1 ]]; then
|
||||
_COPT="-s"
|
||||
fi
|
||||
|
||||
noise "Checking gitea..."
|
||||
|
||||
# get installed version
|
||||
_LOCAL=$("${TEA_DIR}/${TEA_SYM}" -version | awk '{print $3}')
|
||||
# get latest version, strip leading "v" (v1.55.1 -> 1.55.1)
|
||||
_REMOTE=$(curl -s "${TEA_API}" | grep -Po '"tag_name": "\K.*?(?=")')
|
||||
_REMOTE=${_REMOTE#v}
|
||||
|
||||
# API failed, can't run local binary, etc. - something went wrong
|
||||
if [[ -z "${_LOCAL}" || -z "${_REMOTE}" ]]; then
|
||||
noise "Cannot determine Gitea version information"
|
||||
exit 6
|
||||
fi
|
||||
|
||||
# bash doesn't see versions as numbers, but as strings
|
||||
if [[ "${_LOCAL}" != "${_REMOTE}" ]]; then
|
||||
_TEA_NAME="gitea-${_REMOTE}-${TEA_ARCH}"
|
||||
noise "Upgrading gitea - installed ${_LOCAL}, latest ${_REMOTE}"
|
||||
# curl will handle a failure being able to write to output dir, etc.
|
||||
curl ${_COPT} -L --output-dir "${TEA_DIR}" --remote-name-all \
|
||||
"${TEA_DLB}/v${_REMOTE}/${_TEA_NAME}" \
|
||||
"${TEA_DLB}/v${_REMOTE}/${_TEA_NAME}.sha256"
|
||||
if [[ $? -eq 0 ]]; then
|
||||
# downloads were successful and written to disk
|
||||
pushd "$(pwd)" >/dev/null
|
||||
cd "${TEA_DIR}" || (noise "Cannot cd to ${TEA_DIR}"; exit 5)
|
||||
noise "Checking sha256sum..."
|
||||
sha256sum --status -c "${_TEA_NAME}.sha256"
|
||||
if [[ $? -eq 0 ]]; then
|
||||
# sha256sum check passed
|
||||
chmod +x "${_TEA_NAME}"
|
||||
if [[ ${TEA_LINK} -eq 1 ]]; then
|
||||
# user requested replacing symlink
|
||||
if [[ -h "${TEA_SYM}" ]]; then
|
||||
noise "Replacing symlink..."
|
||||
rm -f "${TEA_SYM}"
|
||||
ln -s "${_TEA_NAME}" "${TEA_SYM}"
|
||||
# trust, but verify
|
||||
_TEA_NEW=$("${TEA_DIR}/${TEA_SYM}" -version | awk '{print $3}')
|
||||
if [[ "${_TEA_NEW}" == "${_REMOTE}" ]]; then
|
||||
noise "Gitea binary/symlink upgraded to ${_TEA_NEW}"
|
||||
if [[ ${TEA_HUP} -eq 1 ]]; then
|
||||
# user requested restart
|
||||
noise "Restarting gitea..."
|
||||
${TEA_CMD}
|
||||
else
|
||||
noise "Gitea needs restarted"
|
||||
exit 21
|
||||
fi
|
||||
else
|
||||
noise "Upgrade failed, not restarting gitea"
|
||||
exit 4
|
||||
fi
|
||||
else
|
||||
noise "${TEA_SYM} is not a symlink, not overwriting"
|
||||
exit 3
|
||||
fi
|
||||
else
|
||||
noise "Gitea ${_TEA_NAME} downloaded, ready to upgrade"
|
||||
exit 22
|
||||
fi
|
||||
else
|
||||
noise "Download of ${_TEA_NAME} failed sha256sum, not upgrading"
|
||||
exit 2
|
||||
fi
|
||||
popd >/dev/null
|
||||
else
|
||||
noise "Download of ${_TEA_NAME} and sha256 failed, not upgrading"
|
||||
exit 1
|
||||
fi
|
||||
else
|
||||
noise "Installed gitea is the latest - ${_LOCAL}"
|
||||
fi
|
||||
|
||||
336
doc/SETUP.md
Normal file
|
|
@ -0,0 +1,336 @@
|
|||
# Server Setup
|
||||
|
||||
Debian 12 minimal installation, ensure the SSH server and standard system tools are included.
|
||||
|
||||
|
||||
## Base Configuration
|
||||
|
||||
Internal hostname, replace "myhostname":
|
||||
|
||||
```
|
||||
hostnamectl set-hostname myhostname
|
||||
```
|
||||
|
||||
**/etc/hosts**
|
||||
|
||||
```
|
||||
127.0.0.1 localhost
|
||||
127.0.1.1 myhostname
|
||||
```
|
||||
|
||||
Install packages:
|
||||
|
||||
```
|
||||
apt-get update
|
||||
|
||||
echo "iptables-persistent iptables-persistent/autosave_v4 boolean true" | debconf-set-selections
|
||||
echo "iptables-persistent iptables-persistent/autosave_v6 boolean true" | debconf-set-selections
|
||||
echo "unattended-upgrades unattended-upgrades/enable_auto_updates boolean true" | debconf-set-selections
|
||||
|
||||
apt-get install curl sysstat unattended-upgrades iptables-persistent \
|
||||
man less vim rsync bc net-tools git git-lfs sqlite3 strace sudo \
|
||||
apparmor-utils rsyslog
|
||||
```
|
||||
|
||||
Install packages without `recommends`:
|
||||
|
||||
```
|
||||
apt-get install --no-install-recommends smem \
|
||||
nginx nginx-core libnginx-mod-stream \
|
||||
certbot python3-certbot-nginx
|
||||
```
|
||||
|
||||
Set up services:
|
||||
|
||||
```
|
||||
systemctl disable remote-fs.target rsync.service
|
||||
systemctl enable sysstat unattended-upgrades netfilter-persistent
|
||||
```
|
||||
|
||||
As needed:
|
||||
|
||||
```
|
||||
apt-get update
|
||||
apt-get full-upgrade
|
||||
reboot
|
||||
```
|
||||
|
||||
|
||||
## User Setup
|
||||
|
||||
Add a login user:
|
||||
|
||||
```
|
||||
export MYUSER="frankthetank"
|
||||
useradd -m -d /home/${MYUSER} -s /bin/bash -g users -G sudo ${MYUSER}
|
||||
passwd ${MYUSER}
|
||||
|
||||
mkdir -p /var/xyzzy/bin
|
||||
chown -R ${MYUSER}: /var/xyzzy
|
||||
```
|
||||
|
||||
If `ssh-copy-id` can't be used:
|
||||
|
||||
```
|
||||
mkdir /home/${MYUSER}/.ssh
|
||||
cp /root/.ssh/authorized_keys /home/${MYUSER}/.ssh/
|
||||
chmod 0700 /home/${MYUSER}/.ssh
|
||||
chmod 0600 /home/${MYUSER}/.ssh/authorized_keys
|
||||
chown -R ${MYUSER}:users /home/${MYUSER}/.ssh
|
||||
```
|
||||
|
||||
Disable root login:
|
||||
|
||||
```
|
||||
_SCFG="/etc/ssh/sshd_config"
|
||||
if $(grep -iEq '^PermitRootLogin[[:space:]]+yes' "${_SCFG}"); then
|
||||
sed -i.bak -e 's/^PermitRootLogin.*/PermitRootLogin no/gi' "${_SCFG}"
|
||||
else
|
||||
sed -i.bak -e 's/^#PermitRootLogin.*/PermitRootLogin no/gi' "${_SCFG}"
|
||||
fi
|
||||
```
|
||||
|
||||
After confirming the change is correct:
|
||||
|
||||
```
|
||||
systemctl restart sshd
|
||||
```
|
||||
|
||||
Test logging in again as the user and sudo to root in another term.
|
||||
|
||||
|
||||
## Server Configuration
|
||||
|
||||
Get rid of mouse in `vim`:
|
||||
|
||||
```
|
||||
echo 'set mouse=' >> ~/.vimrc
|
||||
```
|
||||
|
||||
Get rid of bracketed paste:
|
||||
|
||||
```
|
||||
echo 'set enable-bracketed-paste Off' >> ~/.inputrc
|
||||
```
|
||||
|
||||
Enable `sysstat`:
|
||||
|
||||
```
|
||||
sed -i.bak -e 's|^ENABLED=".*"|ENABLED="true"|g' /etc/default/sysstat
|
||||
```
|
||||
|
||||
Configure `unattended-upgrades`:
|
||||
|
||||
```
|
||||
cp 02periodic /etc/apt/apt.conf.d/
|
||||
```
|
||||
|
||||
Configure `iptables` and `ip6tables`:
|
||||
|
||||
```
|
||||
cp rules.* /etc/iptables/
|
||||
```
|
||||
|
||||
Configure tweaks:
|
||||
|
||||
```
|
||||
mkdir /etc/systemd/journald.conf.d
|
||||
mkdir /etc/systemd/system/nginx.service.d
|
||||
cp sysctl.d/local.conf /etc/sysctl.d/
|
||||
cp systemd/journald.conf.d/local.conf \
|
||||
/etc/systemd/journald.conf.d/
|
||||
cp systemd/system/nginx.service.d/override.conf \
|
||||
/etc/systemd/system/nginx.service.d/
|
||||
systemctl daemon-reload
|
||||
```
|
||||
|
||||
|
||||
## Fail2ban Setup
|
||||
|
||||
SSH jail:
|
||||
|
||||
```
|
||||
apt-get install fail2ban
|
||||
cp jail.local /etc/fail2ban/
|
||||
systemctl enable --now fail2ban
|
||||
```
|
||||
|
||||
Maintenance tasks:
|
||||
|
||||
```
|
||||
cp dbpurge.sql /etc/fail2ban/
|
||||
cp f2b-cleanup /etc/cron.weekly/
|
||||
chown root:root /etc/cron.weekly/f2b-cleanup
|
||||
chmod 0755 /etc/cron.weekly/f2b-cleanup
|
||||
|
||||
cp bin/jailstat.sh /var/xyzzy/bin/
|
||||
```
|
||||
|
||||
|
||||
## Nginx Setup
|
||||
|
||||
Gitea first-time setup is easier with nginx + SSL already working.
|
||||
|
||||
#### Basic Prep
|
||||
```
|
||||
cd /etc/nginx/modules-enabled
|
||||
|
||||
rm \
|
||||
50-mod-http-geoip.conf \
|
||||
50-mod-http-image-filter.conf \
|
||||
50-mod-http-xslt-filter.conf \
|
||||
50-mod-mail.conf \
|
||||
70-mod-stream-geoip.conf
|
||||
|
||||
cp security.conf /etc/nginx/conf.d/
|
||||
```
|
||||
|
||||
|
||||
#### Site Prep
|
||||
```
|
||||
mkdir /var/xyzzy/html
|
||||
cp html* /var/xyzzy/html/
|
||||
|
||||
cp xyzzy.ee.conf.bootstrap /etc/nginx/sites-available/xyzzy.ee.conf
|
||||
cp xyzzy.fi.conf.bootstrap /etc/nginx/sites-available/xyzzy.fi.conf
|
||||
cp git.xyzzy.ee.conf.bootstrap /etc/nginx/sites-available/git.xyzzy.ee.conf
|
||||
|
||||
cd /etc/nginx/sites-enabled
|
||||
rm default
|
||||
ln -s /etc/nginx/sites-available/xyzzy.ee.conf 00xyzzy.ee.conf
|
||||
ln -s /etc/nginx/sites-available/xyzzy.fi.conf 01xyzzy.fi.conf
|
||||
ln -s /etc/nginx/sites-available/git.xyzzy.ee.conf 02git.xyzzy.ee.conf
|
||||
nginx -t
|
||||
systemctl restart nginx
|
||||
|
||||
certbot --nginx -d xyzzy.ee,www.xyzzy.ee \
|
||||
--agree-tos -m "hostmaster@xyzzy.ee" --no-eff-email \
|
||||
--deploy-hook "systemctl reload nginx"
|
||||
|
||||
certbot --nginx -d xyzzy.fi,www.xyzzy.fi \
|
||||
--agree-tos -m "hostmaster@xyzzy.fi" --no-eff-email \
|
||||
--deploy-hook "systemctl reload nginx"
|
||||
|
||||
certbot --nginx -d git.xyzzy.ee \
|
||||
--agree-tos -m "hostmaster@xyzzy.ee" --no-eff-email \
|
||||
--deploy-hook "systemctl reload nginx"
|
||||
|
||||
cp xyzzy.ee.conf /etc/nginx/sites-available/xyzzy.ee.conf
|
||||
cp xyzzy.fi.conf /etc/nginx/sites-available/xyzzy.fi.conf
|
||||
cp git.xyzzy.ee.conf /etc/nginx/sites-available/git.xyzzy.ee.conf
|
||||
nginx -t
|
||||
systemctl restart nginx
|
||||
```
|
||||
|
||||
|
||||
## Gitea Setup
|
||||
|
||||
All content lives under `/var/xyzzy`:
|
||||
|
||||
```
|
||||
cp bin/teaup.sh /var/xyzzy/bin/
|
||||
cd /var/xyzzy/bin
|
||||
|
||||
export TVER="1.21.8"
|
||||
curl -L --output-dir /var/xyzzy/bin --remote-name-all \
|
||||
"https://github.com/go-gitea/gitea/releases/download/v${TVER}/gitea-${TVER}-linux-amd64" \
|
||||
"https://github.com/go-gitea/gitea/releases/download/v${TVER}/gitea-${TVER}-linux-amd64.sha256"
|
||||
|
||||
sha256sum -c "gitea-${TVER}-linux-amd64.sha256"
|
||||
chmod +x "gitea-${TVER}-linux-amd64"
|
||||
ln -s "gitea-${TVER}-linux-amd64" gitea
|
||||
```
|
||||
|
||||
Primary `git` user:
|
||||
|
||||
```
|
||||
adduser \
|
||||
--system \
|
||||
--shell /bin/bash \
|
||||
--gecos 'git' \
|
||||
--group \
|
||||
--disabled-password \
|
||||
--home /var/xyzzy/git \
|
||||
git
|
||||
```
|
||||
|
||||
Gitea prep:
|
||||
|
||||
```
|
||||
mkdir -p /var/xyzzy/gitea/{custom,data,log}
|
||||
chown -R git:git /var/xyzzy/gitea/
|
||||
chmod -R 750 /var/xyzzy/gitea/
|
||||
mkdir -p /var/xyzzy/etc/gitea
|
||||
chown root:git /var/xyzzy/etc/gitea
|
||||
chmod 770 /var/xyzzy/etc/gitea
|
||||
|
||||
cp gitea.service /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
```
|
||||
|
||||
Gitea init:
|
||||
```
|
||||
systemctl start gitea.service
|
||||
( browser -> https://git.xyzzy.ee )
|
||||
systemctl stop gitea.service
|
||||
```
|
||||
|
||||
Gitea deploy: (app.ini needs secrets set)
|
||||
|
||||
```
|
||||
cp custom/* /var/xyzzy/gitea/custom/
|
||||
cp app.ini /var/xyzzy/etc/gitea/
|
||||
chmod 750 /var/xyzzy/etc/gitea
|
||||
chmod 640 /var/xyzzy/etc/gitea/app.ini
|
||||
chown root:git /var/xyzzy/etc/gitea/app.ini
|
||||
|
||||
systemctl enable --now gitea.service
|
||||
```
|
||||
|
||||
|
||||
## AppArmor
|
||||
|
||||
```
|
||||
cp apparmor.d/* /etc/apparmor.d/
|
||||
systemctl restart apparmor.service
|
||||
```
|
||||
|
||||
|
||||
## Backup
|
||||
|
||||
See `teabak.sh`; prep: (HCPING needs set in script)
|
||||
|
||||
```
|
||||
groupadd --system bkp
|
||||
mkdir /var/xyzzy/backup
|
||||
chmod 0750 /var/xyzzy/backup
|
||||
chown git:bkp /var/xyzzy/backup
|
||||
|
||||
cp teaback.sh /var/xyzzy/bin/
|
||||
chmod 0755 /var/xyzzy/bin/teabak.sh
|
||||
|
||||
cp teabak.service teabak.timer /etc/systemd/system/
|
||||
systemctl daemon-reload
|
||||
systemctl enable --now teabak.timer
|
||||
```
|
||||
|
||||
Allow restricted backup user to rsync the data:
|
||||
|
||||
```
|
||||
adduser \
|
||||
--shell /bin/bash \
|
||||
--gecos 'reposync' \
|
||||
--ingroup bkp \
|
||||
--disabled-password \
|
||||
--home /home/reposync \
|
||||
reposync
|
||||
```
|
||||
|
||||
The "reposync" user has a restricted `.ssh/authorized_keys` like so:
|
||||
|
||||
```
|
||||
command="/usr/bin/rrsync -ro /var/xyzzy/backup/",no-port-forwarding,no-X11-forwarding,no-agent-forwarding,no-pty,no-user-rc,restrict ssh-ed25519 ...
|
||||
```
|
||||
|
||||
The `rrsync` script is part of the Debian `rsync` package
|
||||
|
||||
35
etc/apparmor.d/usr.sbin.nginx
Normal file
|
|
@ -0,0 +1,35 @@
|
|||
#include <tunables/global>
|
||||
|
||||
/usr/sbin/nginx flags=(complain) {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
#include <abstractions/openssl>
|
||||
#include <abstractions/ssl_certs>
|
||||
#include <abstractions/ssl_keys>
|
||||
|
||||
# privilege drop
|
||||
capability dac_override,
|
||||
capability dac_read_search,
|
||||
capability net_bind_service,
|
||||
capability setgid,
|
||||
capability setuid,
|
||||
|
||||
# abstractions/apache2-common
|
||||
@{PROC}/@{pid}/attr/current rw,
|
||||
|
||||
# nginx operational
|
||||
/etc/letsencrypt/options-ssl-nginx.conf r,
|
||||
/etc/letsencrypt/ssl-dhparams.pem r,
|
||||
/etc/nginx/** r,
|
||||
/run/nginx.pid rw,
|
||||
/usr/lib/nginx/** r,
|
||||
/usr/sbin/nginx mr,
|
||||
/usr/share/nginx/** r,
|
||||
/var/lib/nginx/** rw,
|
||||
/var/log/nginx/error.log w,
|
||||
/var/log/nginx/access.log w,
|
||||
|
||||
# data
|
||||
/var/xyzzy/html/** r,
|
||||
|
||||
}
|
||||
41
etc/apparmor.d/var.xyzzy.bin.gitea
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
#include <tunables/global>
|
||||
|
||||
/var/xyzzy/bin/gitea* flags=(complain) {
|
||||
#include <abstractions/base>
|
||||
#include <abstractions/nameservice>
|
||||
#include <abstractions/user-tmp>
|
||||
|
||||
/dev/tty rw,
|
||||
/etc/gitconfig r,
|
||||
/etc/machine-id r,
|
||||
/etc/mime.types r,
|
||||
/proc/sys/net/core/somaxconn r,
|
||||
/proc/version r,
|
||||
/sys/devices/system/cpu/online r,
|
||||
/sys/kernel/mm/transparent_hugepage/hpage_pmd_size r,
|
||||
/usr/bin/basename mrix,
|
||||
/usr/bin/bash mrix,
|
||||
/usr/bin/cat mrix,
|
||||
/usr/bin/dash mrix,
|
||||
/usr/bin/env rix,
|
||||
/usr/bin/git mrix,
|
||||
/usr/bin/gzip mrix,
|
||||
/usr/lib/git-core/git mrix,
|
||||
/usr/share/git-core/templates r,
|
||||
/usr/share/mime/globs2 r,
|
||||
|
||||
/var/xyzzy/backup/* rw,
|
||||
/var/xyzzy/bin/gitea* mrix,
|
||||
/var/xyzzy/etc/gitea/app.ini r,
|
||||
/var/xyzzy/gitea/** r,
|
||||
/var/xyzzy/gitea/data/gitea-repositories/*/*.git/hooks/* mrix,
|
||||
/var/xyzzy/gitea/data/gitea-repositories/*/*.git/hooks/*.d/* mrix,
|
||||
|
||||
owner /proc/*/cpuset r,
|
||||
owner /var/xyzzy/git/.gitconfig rw,
|
||||
owner /var/xyzzy/git/.gitconfig.lock rw,
|
||||
owner /var/xyzzy/git/.ssh/* rw,
|
||||
owner /var/xyzzy/gitea/data/** rwkl,
|
||||
owner /var/xyzzy/gitea/log/* rw,
|
||||
|
||||
}
|
||||
5
etc/apt/apt.conf.d/02periodic
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
APT::Periodic::Enable "1";
|
||||
APT::Periodic::Update-Package-Lists "1";
|
||||
APT::Periodic::Download-Upgradeable-Packages "1";
|
||||
APT::Periodic::AutocleanInterval "5";
|
||||
APT::Periodic::Unattended-Upgrade "1";
|
||||
5
etc/cron.weekly/f2b-cleanup
Executable file
|
|
@ -0,0 +1,5 @@
|
|||
#!/bin/sh
|
||||
if [ -x /usr/bin/sqlite3 ]; then
|
||||
sqlite3 /var/lib/fail2ban/fail2ban.sqlite3 < /etc/fail2ban/dbpurge.sql
|
||||
fi
|
||||
systemctl restart fail2ban.service
|
||||
3
etc/fail2ban/dbpurge.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
delete from bans where timeofban <= strftime('%s', date('now', '-7 days'));
|
||||
vacuum;
|
||||
.quit
|
||||
3
etc/fail2ban/filter.d/nginx-4xx.conf
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
[Definition]
|
||||
failregex = ^<HOST>.*"(GET|POST).*" (404|444|403|400) .*$
|
||||
ignoreregex =
|
||||
26
etc/fail2ban/jail.local
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
[DEFAULT]
|
||||
ignoreip = 127.0.0.1/8
|
||||
bantime = 3600
|
||||
maxretry = 3
|
||||
backend = systemd
|
||||
destemail = root@localhost
|
||||
|
||||
# filter.d/nginx-4xx.conf
|
||||
# [Definition]
|
||||
# failregex = ^<HOST>.*"(GET|POST).*" (404|444|403|400) .*$
|
||||
# ignoreregex =
|
||||
|
||||
[nginx-4xx]
|
||||
enabled = false
|
||||
port = http,https
|
||||
logpath = /var/log/nginx/access.log
|
||||
maxretry = 10
|
||||
findtime = 3600
|
||||
bantime = 3600
|
||||
|
||||
[nginx-limit-req]
|
||||
enabled = false
|
||||
port = http,https
|
||||
logpath = /var/log/nginx/error.log
|
||||
findtime = 3600
|
||||
bantime = 3600
|
||||
13
etc/iptables/rules.v4
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
*filter
|
||||
:INPUT ACCEPT [0:0]
|
||||
:FORWARD ACCEPT [0:0]
|
||||
:OUTPUT ACCEPT [0:0]
|
||||
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
-A INPUT -p icmp -j ACCEPT
|
||||
-A INPUT -i lo -j ACCEPT
|
||||
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
|
||||
-A INPUT -j REJECT --reject-with icmp-host-prohibited
|
||||
-A FORWARD -j REJECT --reject-with icmp-host-prohibited
|
||||
COMMIT
|
||||
13
etc/iptables/rules.v6
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
*filter
|
||||
:INPUT ACCEPT [0:0]
|
||||
:FORWARD ACCEPT [0:0]
|
||||
:OUTPUT ACCEPT [0:0]
|
||||
-A INPUT -m state --state RELATED,ESTABLISHED -j ACCEPT
|
||||
-A INPUT -p ipv6-icmp -j ACCEPT
|
||||
-A INPUT -i lo -j ACCEPT
|
||||
-A INPUT -p tcp -m state --state NEW -m tcp --dport 22 -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 443 -j ACCEPT
|
||||
-A INPUT -p tcp -m tcp --dport 80 -j ACCEPT
|
||||
-A INPUT -j REJECT --reject-with icmp6-adm-prohibited
|
||||
-A FORWARD -j REJECT --reject-with icmp6-adm-prohibited
|
||||
COMMIT
|
||||
3
etc/letsencrypt/cli.ini
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
max-log-backups = 0
|
||||
preconfigured-renewal = True
|
||||
deploy-hook = systemctl reload nginx
|
||||
14
etc/nginx/conf.d/security.conf
Normal file
|
|
@ -0,0 +1,14 @@
|
|||
|
||||
# https://www.nginx.com/blog/rate-limiting-nginx/
|
||||
# https://nginx.org/en/docs/http/ngx_http_limit_req_module.html
|
||||
limit_req_zone $binary_remote_addr zone=normal:10m rate=20r/s;
|
||||
limit_req zone=normal burst=30 nodelay;
|
||||
limit_req_status 429;
|
||||
|
||||
# https://nginx.org/en/docs/http/ngx_http_core_module.html
|
||||
server_tokens off;
|
||||
keepalive_requests 100;
|
||||
keepalive_timeout 15s;
|
||||
client_body_timeout 20s;
|
||||
client_header_timeout 20s;
|
||||
|
||||
61
etc/nginx/sites-available/git.xyzzy.ee.conf
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
# git.xyzzy.ee
|
||||
|
||||
server {
|
||||
server_name git.xyzzy.ee;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location ~ ^\/(robots\.txt|\.well-known\/security\.txt)$ {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
location / {
|
||||
proxy_pass http://127.0.0.1:3000;
|
||||
proxy_set_header Host $host;
|
||||
proxy_set_header X-Real-IP $remote_addr;
|
||||
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
||||
proxy_set_header X-Forwarded-Proto $scheme;
|
||||
}
|
||||
|
||||
listen [::]:443 ssl; # managed by Certbot
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/git.xyzzy.ee/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/git.xyzzy.ee/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
# https://ssl-config.mozilla.org/
|
||||
add_header Strict-Transport-Security "max-age=15724800" always;
|
||||
|
||||
# OCSP stapling
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/git.xyzzy.ee/chain.pem;
|
||||
resolver 9.9.9.9 8.8.8.8 1.1.1.1;
|
||||
resolver_timeout 5s;
|
||||
|
||||
# https://observatory.mozilla.org
|
||||
# gitea already adds X-Frame-Options SAMEORIGIN
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||
|
||||
# https://csp-evaluator.withgoogle.com/
|
||||
# https://github.com/go-gitea/gitea/issues/305
|
||||
# add_header Content-Security-Policy "upgrade-insecure-requests; default-src 'self'; connect-src 'self'; font-src 'self' data:; form-action 'self'; img-src 'self' data:; object-src 'none'; script-src 'self' 'unsafe-eval' 'unsafe-inline'; style-src 'self' 'unsafe-inline'; worker-src 'self'; frame-src 'self'; frame-ancestors 'self'; manifest-src 'self' data:;";
|
||||
|
||||
}
|
||||
|
||||
server {
|
||||
if ($host = git.xyzzy.ee) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
|
||||
server_name git.xyzzy.ee;
|
||||
return 301 https://git.xyzzy.ee$request_uri;
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
|
||||
15
etc/nginx/sites-available/git.xyzzy.ee.conf.bootstrap
Normal file
|
|
@ -0,0 +1,15 @@
|
|||
# git.xyzzy.ee
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name git.xyzzy.ee;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
108
etc/nginx/sites-available/xyzzy.ee.conf
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
# xyzzy.ee
|
||||
# www.xyzzy.ee
|
||||
|
||||
server {
|
||||
server_name xyzzy.ee;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
listen [::]:443 ssl default_server; # managed by Certbot
|
||||
listen 443 ssl default_server; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/xyzzy.ee/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/xyzzy.ee/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
# https://ssl-config.mozilla.org/
|
||||
add_header Strict-Transport-Security "max-age=15724800" always;
|
||||
|
||||
# OCSP stapling
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/xyzzy.ee/chain.pem;
|
||||
resolver 9.9.9.9 8.8.8.8 1.1.1.1;
|
||||
resolver_timeout 5s;
|
||||
|
||||
# https://observatory.mozilla.org
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||
add_header Content-Security-Policy "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'self';";
|
||||
}
|
||||
|
||||
server {
|
||||
server_name www.xyzzy.ee;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location ~ /\.well-known {
|
||||
allow all;
|
||||
}
|
||||
|
||||
location ~ / {
|
||||
return 301 $scheme://xyzzy.ee$request_uri;
|
||||
}
|
||||
|
||||
listen [::]:443 ssl; # managed by Certbot
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/xyzzy.ee/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/xyzzy.ee/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
# https://ssl-config.mozilla.org/
|
||||
add_header Strict-Transport-Security "max-age=15724800" always;
|
||||
|
||||
# OCSP stapling
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/xyzzy.ee/chain.pem;
|
||||
resolver 9.9.9.9 8.8.8.8 1.1.1.1;
|
||||
resolver_timeout 5s;
|
||||
|
||||
# https://observatory.mozilla.org
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||
add_header Content-Security-Policy "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'self';";
|
||||
}
|
||||
|
||||
server {
|
||||
if ($host = xyzzy.ee) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name xyzzy.ee;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
|
||||
server {
|
||||
if ($host = www.xyzzy.ee) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name www.xyzzy.ee;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name _;
|
||||
return 301 https://xyzzy.ee$request_uri;
|
||||
}
|
||||
|
||||
32
etc/nginx/sites-available/xyzzy.ee.conf.bootstrap
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# xyzzy.ee
|
||||
# www.xyzzy.ee
|
||||
|
||||
server {
|
||||
listen 80 default_server;
|
||||
listen [::]:80 default_server;
|
||||
server_name xyzzy.ee;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name www.xyzzy.ee;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location ~ /\.well-known {
|
||||
allow all;
|
||||
}
|
||||
|
||||
location ~ / {
|
||||
return 301 $scheme://xyzzy.ee$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
101
etc/nginx/sites-available/xyzzy.fi.conf
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
# xyzzy.fi
|
||||
# www.xyzzy.fi
|
||||
|
||||
server {
|
||||
server_name xyzzy.fi;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
listen [::]:443 ssl; # managed by Certbot
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/xyzzy.fi/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/xyzzy.fi/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
# https://ssl-config.mozilla.org/
|
||||
add_header Strict-Transport-Security "max-age=15724800" always;
|
||||
|
||||
# OCSP stapling
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/xyzzy.fi/chain.pem;
|
||||
resolver 9.9.9.9 8.8.8.8 1.1.1.1;
|
||||
resolver_timeout 5s;
|
||||
|
||||
# https://observatory.mozilla.org
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||
add_header Content-Security-Policy "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'self';";
|
||||
}
|
||||
|
||||
server {
|
||||
server_name www.xyzzy.fi;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location ~ /\.well-known {
|
||||
allow all;
|
||||
}
|
||||
|
||||
location ~ / {
|
||||
return 301 $scheme://xyzzy.fi$request_uri;
|
||||
}
|
||||
|
||||
listen [::]:443 ssl; # managed by Certbot
|
||||
listen 443 ssl; # managed by Certbot
|
||||
ssl_certificate /etc/letsencrypt/live/xyzzy.fi/fullchain.pem; # managed by Certbot
|
||||
ssl_certificate_key /etc/letsencrypt/live/xyzzy.fi/privkey.pem; # managed by Certbot
|
||||
include /etc/letsencrypt/options-ssl-nginx.conf; # managed by Certbot
|
||||
ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem; # managed by Certbot
|
||||
|
||||
# https://ssl-config.mozilla.org/
|
||||
add_header Strict-Transport-Security "max-age=15724800" always;
|
||||
|
||||
# OCSP stapling
|
||||
ssl_stapling on;
|
||||
ssl_stapling_verify on;
|
||||
ssl_trusted_certificate /etc/letsencrypt/live/xyzzy.fi/chain.pem;
|
||||
resolver 9.9.9.9 8.8.8.8 1.1.1.1;
|
||||
resolver_timeout 5s;
|
||||
|
||||
# https://observatory.mozilla.org
|
||||
add_header X-Frame-Options "SAMEORIGIN";
|
||||
add_header X-Content-Type-Options "nosniff";
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Referrer-Policy "strict-origin-when-cross-origin";
|
||||
add_header Content-Security-Policy "default-src 'none'; img-src 'self'; script-src 'self'; style-src 'self'; base-uri 'self'; form-action 'self'; frame-ancestors 'self';";
|
||||
}
|
||||
|
||||
server {
|
||||
if ($host = xyzzy.fi) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name xyzzy.fi;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
|
||||
server {
|
||||
if ($host = www.xyzzy.fi) {
|
||||
return 301 https://$host$request_uri;
|
||||
} # managed by Certbot
|
||||
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name www.xyzzy.fi;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
return 404; # managed by Certbot
|
||||
}
|
||||
|
||||
32
etc/nginx/sites-available/xyzzy.fi.conf.bootstrap
Normal file
|
|
@ -0,0 +1,32 @@
|
|||
# xyzzy.fi
|
||||
# www.xyzzy.fi
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name xyzzy.fi;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location / {
|
||||
try_files $uri $uri/ =404;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
server {
|
||||
listen 80;
|
||||
listen [::]:80;
|
||||
server_name www.xyzzy.fi;
|
||||
root /var/xyzzy/html;
|
||||
index index.html;
|
||||
|
||||
location ~ /\.well-known {
|
||||
allow all;
|
||||
}
|
||||
|
||||
location ~ / {
|
||||
return 301 $scheme://xyzzy.fi$request_uri;
|
||||
}
|
||||
}
|
||||
|
||||
1
etc/sysctl.d/local.conf
Normal file
|
|
@ -0,0 +1 @@
|
|||
vm.swappiness = 10
|
||||
2
etc/systemd/journald.conf.d/local.conf
Normal file
|
|
@ -0,0 +1,2 @@
|
|||
[Journal]
|
||||
MaxRetentionSec=1week
|
||||
31
etc/systemd/system/gitea.service
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
[Unit]
|
||||
Description=Gitea
|
||||
After=syslog.target
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
# Modify these two values and uncomment them if you have
|
||||
# repos with lots of files and get an HTTP error 500 because
|
||||
# of that
|
||||
###
|
||||
#LimitMEMLOCK=infinity
|
||||
#LimitNOFILE=65535
|
||||
###
|
||||
RestartSec=2s
|
||||
Type=simple
|
||||
User=git
|
||||
Group=git
|
||||
WorkingDirectory=/var/xyzzy/gitea/
|
||||
ExecStart=/var/xyzzy/bin/gitea web --config /var/xyzzy/etc/gitea/app.ini
|
||||
Restart=always
|
||||
Environment=USER=git HOME=/var/xyzzy/git GITEA_WORK_DIR=/var/xyzzy/gitea
|
||||
Environment=PATH=/var/xyzzy/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
|
||||
# If you want to bind Gitea to a port below 1024, uncomment
|
||||
# the two values below, or use socket activation to pass Gitea its ports as above
|
||||
###
|
||||
#CapabilityBoundingSet=CAP_NET_BIND_SERVICE
|
||||
#AmbientCapabilities=CAP_NET_BIND_SERVICE
|
||||
###
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
3
etc/systemd/system/nginx.service.d/override.conf
Normal file
|
|
@ -0,0 +1,3 @@
|
|||
# https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=876365
|
||||
[Service]
|
||||
ExecStartPost=/usr/bin/sleep 0.1
|
||||
10
etc/systemd/system/teabak.service
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Gitea Backup
|
||||
Wants=teabak.timer
|
||||
|
||||
[Service]
|
||||
Type=oneshot
|
||||
ExecStart=/var/xyzzy/bin/teabak.sh
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
10
etc/systemd/system/teabak.timer
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[Unit]
|
||||
Description=Gitea Backup Timer
|
||||
Requires=teabak.service
|
||||
|
||||
[Timer]
|
||||
Unit=teabak.service
|
||||
OnCalendar=*-*-* 00,08,16:00:00
|
||||
|
||||
[Install]
|
||||
WantedBy=timers.target
|
||||
151
gitea/app.ini
Normal file
|
|
@ -0,0 +1,151 @@
|
|||
# https://github.com/go-gitea/gitea/blob/main/custom/conf/app.example.ini
|
||||
|
||||
APP_NAME = xyzzy gitea
|
||||
RUN_USER = git
|
||||
RUN_MODE = prod
|
||||
# same as $GITEA_WORK_DIR in systemd unit env
|
||||
WORK_PATH = /var/xyzzy/gitea
|
||||
|
||||
[ui]
|
||||
DEFAULT_THEME = arc-green
|
||||
SHOW_USER_EMAIL = false
|
||||
AMBIGUOUS_UNICODE_DETECTION = false
|
||||
|
||||
[attachment]
|
||||
ALLOWED_TYPES = "*/*"
|
||||
|
||||
[ui.meta]
|
||||
AUTHOR = xyzzy
|
||||
DESCRIPTION = git repositories
|
||||
|
||||
[database]
|
||||
DB_TYPE = sqlite3
|
||||
HOST = 127.0.0.1:3306
|
||||
NAME = gitea
|
||||
USER = gitea
|
||||
PASSWD =
|
||||
SCHEMA =
|
||||
SSL_MODE = disable
|
||||
CHARSET = utf8
|
||||
PATH = /var/xyzzy/gitea/data/gitea.db
|
||||
LOG_SQL = false
|
||||
AUTO_MIGRATION = true
|
||||
|
||||
[repository]
|
||||
ROOT = /var/xyzzy/gitea/data/gitea-repositories
|
||||
DEFAULT_BRANCH = main
|
||||
DISABLE_STARS = true
|
||||
|
||||
[repository.signing]
|
||||
DEFAULT_TRUST_MODE = committer
|
||||
|
||||
[server]
|
||||
SSH_DOMAIN = git.xyzzy.ee
|
||||
DOMAIN = git.xyzzy.ee
|
||||
ROOT_URL = https://git.xyzzy.ee/
|
||||
# https://github.com/go-gitea/gitea/issues/9427
|
||||
HTTP_ADDR = 127.0.0.1
|
||||
HTTP_PORT = 3000
|
||||
DISABLE_SSH = false
|
||||
SSH_PORT = 22
|
||||
LFS_START_SERVER = true
|
||||
LFS_JWT_SECRET = (REDACTED)
|
||||
OFFLINE_MODE = true
|
||||
LANDING_PAGE = home
|
||||
# if needed, see app.example.ini
|
||||
;STATIC_ROOT_PATH =
|
||||
;APP_DATA_PATH = data
|
||||
|
||||
[lfs]
|
||||
STORAGE_TYPE = local
|
||||
PATH = /var/xyzzy/gitea/data/lfs
|
||||
|
||||
[mailer]
|
||||
ENABLED = false
|
||||
|
||||
[service]
|
||||
REGISTER_EMAIL_CONFIRM = false
|
||||
REGISTER_MANUAL_CONFIRM = true
|
||||
ENABLE_NOTIFY_MAIL = false
|
||||
DISABLE_REGISTRATION = true
|
||||
ALLOW_ONLY_INTERNAL_REGISTRATION = true
|
||||
ALLOW_ONLY_EXTERNAL_REGISTRATION = false
|
||||
ENABLE_CAPTCHA = false
|
||||
REQUIRE_CAPTCHA_FOR_LOGIN = false
|
||||
REQUIRE_SIGNIN_VIEW = false
|
||||
DEFAULT_KEEP_EMAIL_PRIVATE = true
|
||||
DEFAULT_ALLOW_CREATE_ORGANIZATION = true
|
||||
DEFAULT_ENABLE_TIMETRACKING = true
|
||||
NO_REPLY_ADDRESS = noreply.xyzzy.ee
|
||||
ENABLE_USER_HEATMAP = false
|
||||
|
||||
[service.explore]
|
||||
DISABLE_USERS_PAGE = true
|
||||
|
||||
[picture]
|
||||
DISABLE_GRAVATAR = true
|
||||
ENABLE_FEDERATED_AVATAR = false
|
||||
|
||||
[openid]
|
||||
ENABLE_OPENID_SIGNIN = false
|
||||
ENABLE_OPENID_SIGNUP = false
|
||||
|
||||
[oauth2]
|
||||
ENABLE = false
|
||||
JWT_SECRET = (REDACTED)
|
||||
|
||||
[session]
|
||||
PROVIDER = file
|
||||
COOKIE_SECURE = true
|
||||
COOKIE_NAME = __Host-gitea_session
|
||||
|
||||
[log]
|
||||
MODE = console
|
||||
LEVEL = critical
|
||||
ROOT_PATH = /var/xyzzy/gitea/log
|
||||
COLORIZE = false
|
||||
logger.access.MODE =
|
||||
logger.router.MODE =
|
||||
logger.xorm.MODE =
|
||||
|
||||
[log.console]
|
||||
COLORIZE = false
|
||||
|
||||
[cron.update_mirrors]
|
||||
SCHEDULE = @midnight
|
||||
|
||||
[cron.delete_old_actions]
|
||||
ENABLED = true
|
||||
SCHEDULE = @midnight
|
||||
OLDER_THAN = 8760h
|
||||
|
||||
[cron.delete_old_system_notices]
|
||||
ENABLED = true
|
||||
SCHEDULE = @midnight
|
||||
OLDER_THAN = 720h
|
||||
|
||||
# https://pkg.go.dev/time#pkg-constants
|
||||
[time]
|
||||
FORMAT = RFC3339
|
||||
|
||||
[mirror]
|
||||
DEFAULT_INTERVAL = 4h
|
||||
|
||||
[security]
|
||||
INSTALL_LOCK = true
|
||||
LOGIN_REMEMBER_DAYS = 365
|
||||
INTERNAL_TOKEN = (REDACTED)
|
||||
PASSWORD_HASH_ALGO = pbkdf2
|
||||
DISABLE_QUERY_AUTH_TOKEN = true
|
||||
|
||||
[other]
|
||||
SHOW_FOOTER_TEMPLATE_LOAD_TIME = false
|
||||
ENABLE_FEED = false
|
||||
|
||||
[federation]
|
||||
ENABLED = false
|
||||
SHARE_USER_STATISTICS = false
|
||||
|
||||
[actions]
|
||||
ENABLED = false
|
||||
|
||||
10
gitea/custom/templates/home.tmpl
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
{{template "base/head" .}}
|
||||
<div role="main" aria-label="{{if .IsSigned}}{{ctx.Locale.Tr "dashboard"}}{{else}}{{ctx.Locale.Tr "home"}}{{end}}" class="page-content home">
|
||||
<div class="gt-mb-5 gt-px-5">
|
||||
<div class="center">
|
||||
<div class="hero">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
{{template "base/footer" .}}
|
||||
1
html/.well-known/security.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
Contact: https://xyzzy.ee
|
||||
BIN
html/favicon.ico
Normal file
|
After Width: | Height: | Size: 31 KiB |
163
html/index.css
Normal file
|
|
@ -0,0 +1,163 @@
|
|||
header,section{
|
||||
display:block;
|
||||
}
|
||||
body{
|
||||
font-size:16px;
|
||||
margin:0 auto;
|
||||
line-height:1.4;
|
||||
background:#0b0c0d;
|
||||
color:#d4d4d4;
|
||||
font-family:"Noto Sans", Futura, Verdana, "Liberation Sans", sans-serif;
|
||||
}
|
||||
a{
|
||||
color:#c79908;
|
||||
text-decoration:none;
|
||||
}
|
||||
a:hover{
|
||||
text-decoration:underline;
|
||||
}
|
||||
::selection {
|
||||
color:#000;
|
||||
background:#7a9e55;
|
||||
}
|
||||
h1{
|
||||
font-size:2em;
|
||||
margin:.67em 0;
|
||||
}
|
||||
kbd {
|
||||
border-radius: 3px;
|
||||
padding: 1px 2px 0;
|
||||
border: 1px solid #666666;
|
||||
}
|
||||
#page{
|
||||
position:relative;
|
||||
}
|
||||
#header{
|
||||
padding-top:50px;
|
||||
transform:translate3d(0,0,0);
|
||||
}
|
||||
.title-wrapper{
|
||||
text-align:center;
|
||||
}
|
||||
.content{
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
padding:1px 20px;
|
||||
position:relative;
|
||||
z-index:2;
|
||||
min-width:270px;
|
||||
}
|
||||
.title-group.animate{
|
||||
animation:slide-fade-in .8s ease;
|
||||
}
|
||||
.title{
|
||||
font-size:42px;
|
||||
line-height:1.2;
|
||||
margin:40px 0 0;
|
||||
word-wrap:break-word;
|
||||
}
|
||||
.title a:active{
|
||||
transform:translateY(1px);
|
||||
}
|
||||
.title a{
|
||||
color:#e4e4e4;
|
||||
display:block;
|
||||
text-decoration:none;
|
||||
}
|
||||
.description{
|
||||
color:#7a9e55;
|
||||
margin:50px 0 0;
|
||||
display:block;
|
||||
}
|
||||
.title+.description{
|
||||
margin-top:10px!important;
|
||||
}
|
||||
.footdesc{
|
||||
color:#666666;
|
||||
margin:20px 0 0;
|
||||
display:block;
|
||||
font-size: 14px;
|
||||
}
|
||||
.footlink {
|
||||
text-align: center;
|
||||
}
|
||||
.footlink.animate {
|
||||
animation:slide-fade-in .8s ease;
|
||||
}
|
||||
.middle {
|
||||
overflow: auto;
|
||||
margin: auto;
|
||||
display: inline;
|
||||
text-align: center;
|
||||
vertical-align: middle;
|
||||
}
|
||||
@media screen and (max-width:568px){
|
||||
.content{
|
||||
padding:1px 10px;
|
||||
}
|
||||
.title{
|
||||
font-size:36px;
|
||||
margin-top:30px;
|
||||
}
|
||||
.description{
|
||||
margin-top:35px;
|
||||
max-width:80%;
|
||||
margin-left:auto;
|
||||
margin-right:auto;
|
||||
}
|
||||
.title+.description{
|
||||
margin-top:4px!important;
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slide-fade-in{
|
||||
0%{
|
||||
opacity:0;
|
||||
transform:translate3d(0,20px,0);
|
||||
}
|
||||
to{
|
||||
opacity:1;
|
||||
transform:translate3d(0,0,0);
|
||||
}
|
||||
}
|
||||
|
||||
.divTable {
|
||||
font-size: 16px;
|
||||
line-height: 2.0;
|
||||
display: table;
|
||||
margin: auto;
|
||||
border: 1px solid #444;
|
||||
}
|
||||
.divTable.animate {
|
||||
animation:slide-fade-in .8s ease;
|
||||
}
|
||||
.divTableRow {
|
||||
display: table-row;
|
||||
}
|
||||
.divTableHeading {
|
||||
display: table-header-group;
|
||||
background-color: #ddd;
|
||||
}
|
||||
.divTableCell, .divTableHead {
|
||||
vertical-align: middle;
|
||||
display: table-cell;
|
||||
padding: 5px 10px;
|
||||
border: 1px solid #444;
|
||||
}
|
||||
.divTableHeading {
|
||||
display: table-header-group;
|
||||
background-color: #ddd;
|
||||
font-weight: bold;
|
||||
}
|
||||
.divTableFoot {
|
||||
display: table-footer-group;
|
||||
font-weight: bold;
|
||||
background-color: #ddd;
|
||||
}
|
||||
.divTableBody {
|
||||
display: table-row-group;
|
||||
}
|
||||
.valign {
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
41
html/index.html
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>xyzzy</title>
|
||||
<meta name="description" content="a maze of twisty little passages">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" media="screen" href="index.css">
|
||||
<link rel="shortcut icon" href="favicon.ico">
|
||||
</head>
|
||||
|
||||
<body>
|
||||
|
||||
<header id="header">
|
||||
<div class="title-wrapper content">
|
||||
<div class="title-group">
|
||||
<h1 class="title">xyzzy</h1>
|
||||
<span class="description">
|
||||
<em>a personal domain</em>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main id="main">
|
||||
<div class="content middle">
|
||||
<p><a target="_blank" href="https://en.wikipedia.org/wiki/Xyzzy_(computing)">The magic word XYZZY</a></p>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<footer id="footer">
|
||||
<div class="content middle">
|
||||
<span class="footdesc">[ .ee | .fi ]</span>
|
||||
</div>
|
||||
</footer>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
|
||||
8
html/robots.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
User-Agent: *
|
||||
|
||||
# credit: jonty, asimov
|
||||
Disallow: /harming/humans
|
||||
Disallow: /ignoring/human/orders
|
||||
Disallow: /harm/to/self
|
||||
|
||||
Allow: /
|
||||