Initial infrastructure: Caddy reverse proxy and Forgejo git server
- Ubuntu 24.04 base on dedicated hardware with software RAID 1 - Docker Compose stacks for Caddy and Forgejo (PostgreSQL-backed) - Automatic TLS via Let's Encrypt - SSH hardening, UFW firewall, fail2ban - Setup documentation in docs/setup.md
This commit is contained in:
commit
648d4e6b98
2 changed files with 224 additions and 0 deletions
60
README.md
Normal file
60
README.md
Normal file
|
|
@ -0,0 +1,60 @@
|
||||||
|
# Infrastructure
|
||||||
|
|
||||||
|
Self-hosted development and deployment infrastructure for personal technical projects.
|
||||||
|
|
||||||
|
Runs a private Git forge (Forgejo), an automated reverse proxy with TLS (Caddy), and serves prototype applications under development.
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
- **Host:** Ubuntu 24.04 LTS on dedicated hardware (Hetzner, Falkenstein)
|
||||||
|
- **Storage:** Software RAID 1 for the operating system, separate disk for non-critical data
|
||||||
|
- **Orchestration:** Docker Compose
|
||||||
|
- **Reverse proxy:** Caddy 2, with automatic Let's Encrypt certificates
|
||||||
|
- **Git hosting:** Forgejo with PostgreSQL backend
|
||||||
|
- **Firewall:** UFW, restricting inbound traffic to SSH, HTTP, HTTPS, and Git-over-SSH
|
||||||
|
- **Intrusion prevention:** fail2ban on SSH
|
||||||
|
|
||||||
|
## Services
|
||||||
|
|
||||||
|
| Service | URL | Purpose |
|
||||||
|
|---------|--------------------------|--------------------------------|
|
||||||
|
| Forgejo | https://git.stifting.at | Self-hosted Git and CI/CD |
|
||||||
|
| App | https://bim.stifting.at | Currently hosted prototype |
|
||||||
|
|
||||||
|
## Repository layout
|
||||||
|
|
||||||
|
```
|
||||||
|
.
|
||||||
|
├── caddy/ # Reverse proxy configuration
|
||||||
|
│ ├── docker-compose.yml
|
||||||
|
│ └── Caddyfile
|
||||||
|
├── forgejo/ # Git server configuration
|
||||||
|
│ ├── docker-compose.yml
|
||||||
|
│ └── .env.example
|
||||||
|
├── docs/ # Setup notes and runbooks
|
||||||
|
│ └── setup.md
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Bootstrapping a new host
|
||||||
|
|
||||||
|
See [docs/setup.md](docs/setup.md) for the full installation procedure.
|
||||||
|
|
||||||
|
High-level steps:
|
||||||
|
|
||||||
|
1. Provision Ubuntu 24.04 via `installimage` with RAID 1
|
||||||
|
2. Harden SSH, create an admin user, enable UFW and fail2ban
|
||||||
|
3. Install Docker and create the shared `web` network
|
||||||
|
4. Deploy Caddy, then Forgejo
|
||||||
|
5. Configure DNS records for the relevant subdomains
|
||||||
|
|
||||||
|
## Security notes
|
||||||
|
|
||||||
|
- SSH uses key-only authentication; root login is disabled
|
||||||
|
- Secrets (`.env`, passwords) are never committed; templates are provided as `.env.example`
|
||||||
|
- Unattended security upgrades are enabled
|
||||||
|
- TLS certificates are issued and renewed automatically via ACME
|
||||||
|
|
||||||
|
## License
|
||||||
|
|
||||||
|
MIT
|
||||||
164
docs/setup.md
Normal file
164
docs/setup.md
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
# Host setup guide
|
||||||
|
|
||||||
|
Step-by-step procedure for provisioning a new host running this infrastructure.
|
||||||
|
|
||||||
|
## 1. Operating system installation
|
||||||
|
|
||||||
|
From the Hetzner rescue system, use `installimage` with the following configuration:
|
||||||
|
|
||||||
|
- **Image:** Ubuntu 24.04 LTS
|
||||||
|
- **RAID:** Software RAID 1 across two NVMe drives for `/`, `/boot`, and swap
|
||||||
|
- **Additional disks:** Formatted ext4 and mounted at `/data` for non-critical storage
|
||||||
|
- **Hostname:** set as appropriate
|
||||||
|
|
||||||
|
## 2. Hardening
|
||||||
|
|
||||||
|
After the first boot, performed as `root`:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
apt update && apt upgrade -y
|
||||||
|
apt install -y curl wget git vim htop tmux ufw fail2ban unattended-upgrades \
|
||||||
|
ca-certificates gnupg lsb-release
|
||||||
|
|
||||||
|
timedatectl set-timezone Europe/Vienna
|
||||||
|
|
||||||
|
adduser <admin-user>
|
||||||
|
usermod -aG sudo <admin-user>
|
||||||
|
|
||||||
|
# Copy authorized_keys from root to the new user
|
||||||
|
mkdir -p /home/<admin-user>/.ssh
|
||||||
|
cp /root/.ssh/authorized_keys /home/<admin-user>/.ssh/
|
||||||
|
chown -R <admin-user>:<admin-user> /home/<admin-user>/.ssh
|
||||||
|
chmod 700 /home/<admin-user>/.ssh
|
||||||
|
chmod 600 /home/<admin-user>/.ssh/authorized_keys
|
||||||
|
```
|
||||||
|
|
||||||
|
### SSH hardening
|
||||||
|
|
||||||
|
Create `/etc/ssh/sshd_config.d/99-hardening.conf`:
|
||||||
|
|
||||||
|
```
|
||||||
|
PermitRootLogin no
|
||||||
|
PasswordAuthentication no
|
||||||
|
PubkeyAuthentication yes
|
||||||
|
KbdInteractiveAuthentication no
|
||||||
|
AllowUsers <admin-user>
|
||||||
|
X11Forwarding no
|
||||||
|
AllowAgentForwarding no
|
||||||
|
ClientAliveInterval 300
|
||||||
|
ClientAliveCountMax 2
|
||||||
|
```
|
||||||
|
|
||||||
|
Validate and reload:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sshd -t && systemctl reload ssh
|
||||||
|
```
|
||||||
|
|
||||||
|
### Firewall
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ufw default deny incoming
|
||||||
|
ufw default allow outgoing
|
||||||
|
ufw allow 22/tcp comment 'SSH'
|
||||||
|
ufw allow 80/tcp comment 'HTTP'
|
||||||
|
ufw allow 443/tcp comment 'HTTPS'
|
||||||
|
ufw allow 2222/tcp comment 'Forgejo Git SSH'
|
||||||
|
ufw enable
|
||||||
|
```
|
||||||
|
|
||||||
|
### fail2ban
|
||||||
|
|
||||||
|
`/etc/fail2ban/jail.local`:
|
||||||
|
|
||||||
|
```ini
|
||||||
|
[DEFAULT]
|
||||||
|
bantime = 1h
|
||||||
|
findtime = 10m
|
||||||
|
maxretry = 5
|
||||||
|
backend = systemd
|
||||||
|
|
||||||
|
[sshd]
|
||||||
|
enabled = true
|
||||||
|
port = 22
|
||||||
|
```
|
||||||
|
|
||||||
|
Then enable:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl enable --now fail2ban
|
||||||
|
```
|
||||||
|
|
||||||
|
### Unattended upgrades
|
||||||
|
|
||||||
|
```bash
|
||||||
|
dpkg-reconfigure -plow unattended-upgrades
|
||||||
|
```
|
||||||
|
|
||||||
|
In `/etc/apt/apt.conf.d/50unattended-upgrades`:
|
||||||
|
|
||||||
|
```
|
||||||
|
Unattended-Upgrade::Automatic-Reboot "true";
|
||||||
|
Unattended-Upgrade::Automatic-Reboot-Time "04:00";
|
||||||
|
```
|
||||||
|
|
||||||
|
## 3. Docker
|
||||||
|
|
||||||
|
```bash
|
||||||
|
install -m 0755 -d /etc/apt/keyrings
|
||||||
|
curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
|
||||||
|
chmod a+r /etc/apt/keyrings/docker.asc
|
||||||
|
|
||||||
|
echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] \
|
||||||
|
https://download.docker.com/linux/ubuntu $(. /etc/os-release && echo $VERSION_CODENAME) stable" \
|
||||||
|
| tee /etc/apt/sources.list.d/docker.list
|
||||||
|
|
||||||
|
apt update
|
||||||
|
apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
|
||||||
|
|
||||||
|
usermod -aG docker <admin-user>
|
||||||
|
```
|
||||||
|
|
||||||
|
Configure `/etc/docker/daemon.json` for log rotation:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"log-driver": "json-file",
|
||||||
|
"log-opts": {
|
||||||
|
"max-size": "10m",
|
||||||
|
"max-file": "3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Start Docker and create the shared network:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
systemctl enable --now docker
|
||||||
|
docker network create web
|
||||||
|
```
|
||||||
|
|
||||||
|
## 4. DNS
|
||||||
|
|
||||||
|
Set the following records for your domain:
|
||||||
|
|
||||||
|
| Type | Name | Value |
|
||||||
|
|------|------|---------------|
|
||||||
|
| A | git | <server-ipv4> |
|
||||||
|
| A | bim | <server-ipv4> |
|
||||||
|
| AAAA | git | <server-ipv6> |
|
||||||
|
| AAAA | bim | <server-ipv6> |
|
||||||
|
|
||||||
|
## 5. Deploy services
|
||||||
|
|
||||||
|
```bash
|
||||||
|
cd ~/projects/infra/caddy
|
||||||
|
docker compose up -d
|
||||||
|
|
||||||
|
cd ~/projects/infra/forgejo
|
||||||
|
cp .env.example .env
|
||||||
|
# Edit .env and set a strong DB_PASSWORD (e.g. openssl rand -base64 32)
|
||||||
|
docker compose up -d
|
||||||
|
```
|
||||||
|
|
||||||
|
Complete the Forgejo setup via the web interface.
|
||||||
Loading…
Add table
Reference in a new issue