diff --git a/Makefile b/Makefile index 8378b8a..f1f2a6a 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,7 @@ MODULES += mastodon MODULES += matrix MODULES += nextcloud MODULES += mobilizon +MODULES += gitea #MODULES += pixelfed include env.production @@ -68,6 +69,12 @@ data/%/secrets: echo >>$@ "export $(GET_MODULE)_CLIENT_SECRET=$(call RAND,20)" echo >>$@ "export $(GET_MODULE)_SESSION_SECRET=$(call RAND,20)" +data/gitea/secrets: data/gitea/host-setup.done +data/gitea/host-setup.done: + sudo ./gitea/host-setup.sh + mkdir -p $(dir $@) + touch $@ + keycloak-setup: secrets-setup docker exec keycloak /setup.sh diff --git a/README.md b/README.md index 7243285..c6baf12 100644 --- a/README.md +++ b/README.md @@ -4,17 +4,13 @@ Infrastructure for the self-hosted, single-sign-on, community-run services. * Set the domain name in `env.production` * Create the DNS entries in the domain for `login`, `cloud`, `matrix`, `dashboard`, `docs` and maybe more. -* Install dependencies: +* Install dependencies (note that `docker-compose 1.25` breaks environment variables as we use them): ``` -apt install jq docker-compose -apt install prometheus +apt install python3-pip prometheus +pip3 install docker-compose ``` -* Setup each of the services. `keycloak` and `nginx` are required to start the others: - -``` -./keycloak/setup -./nginx/setup -./start-all -``` +* `make run` to startup all of the containers +* `make keycloak-setup` to setup all of the OIDC links +* `make down` to stop everything diff --git a/gitea.yaml b/gitea.yaml new file mode 100644 index 0000000..c2ea9db --- /dev/null +++ b/gitea.yaml @@ -0,0 +1,69 @@ +# gitea requires ssh access from the host machine, which needs special setup +# In order to create the git user and auth keys, you need to run: +# +# sudo gitea/setup.sh +# +version: "3" + +services: + gitea: + image: gitea/gitea:1.17.3 + container_name: gitea + env_file: + - ./env.production + environment: + - USER_UID=2222 # must match git user on host system + - USER_GID=2222 + - GITEA_CLIENT_SECRET=${GITEA_CLIENT_SECRET} + - GITEA_ADMIN_PASSWORD=${GITEA_ADMIN_PASSWORD} + - GITEA__database__DB_TYPE=postgres + - GITEA__database__HOST=gitea-db:5432 + - GITEA__database__NAME=gitea + - GITEA__database__USER=gitea + - GITEA__database__PASSWD=gitea + - GITEA__oauth2_client__ENABLE_AUTO_REGISTRATION=true + - GITEA__openid__ENABLE_OPENID_SIGNIN=true + - GITEA__openid__ENABLE_OPENID_SIGNUP=false + - GITEA__service__DISABLE_REGISTRATION=true + - GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION=true + - GITEA__repository__DEFAULT_BRANCH=main + - GITEA__server__ROOT_URL=https://${GITEA_HOSTNAME}.${DOMAIN_NAME}/ + - GITEA__server__SSH_DOMAIN=${GITEA_HOSTNAME}.${DOMAIN_NAME} + - GITEA__security__SECRET_KEY=${GITEA_SESSION_SECRET} + - GITEA__security__INSTALL_LOCK=true + entrypoint: ["/setup.sh"] + volumes: + - ./gitea/setup.sh:/setup.sh:ro + - ./data/gitea:/data + - /etc/timezone:/etc/timezone:ro + - /etc/localtime:/etc/localtime:ro + - /home/git/.ssh/:/data/git/.ssh + ports: +# - "3030:3000" + - "2222:22" # route host port 2222 to container port 22 for inbound ssh + restart: always + depends_on: + - gitea-db + + gitea-db: + image: postgres:13.4-alpine + container_name: gitea-db + restart: always + environment: + - POSTGRES_USER=gitea + - POSTGRES_PASSWORD=gitea + - POSTGRES_DB=gitea + volumes: + - ./data/gitea/postgres:/var/lib/postgresql/data + + # add the gitea nginx configuration into the nginx volume + nginx: + volumes: + - ./gitea/nginx.conf:/etc/nginx/templates/gitea.conf.template:ro + + # add the gitea client secrets to the keycloak-setup volume + keycloak-setup: + env_file: + - data/gitea/secrets + volumes: + - ./gitea/keycloak.sh:/keycloak-setup/gitea.sh:ro diff --git a/gitea/README.md b/gitea/README.md index ef1b0be..2930b65 100644 --- a/gitea/README.md +++ b/gitea/README.md @@ -1,3 +1,6 @@ # gitea -OIDC setup is now automated +There is still a sudo step that has to happen on the host. + +OIDC setup is now automated in the container. + diff --git a/gitea/docker-compose.yaml b/gitea/docker-compose.yaml deleted file mode 100644 index 0fee41d..0000000 --- a/gitea/docker-compose.yaml +++ /dev/null @@ -1,46 +0,0 @@ -version: "3" - -networks: - gitea: - external: false - -services: - gitea: - image: gitea/gitea:1.16.6 - env_file: - - ../env.production - - env.production - - ../data/gitea/env.secrets - environment: - - USER_UID=2222 # must match git user on host system - - USER_GID=2222 - - GITEA__database__DB_TYPE=postgres - - GITEA__database__HOST=db:5432 - - GITEA__database__NAME=gitea - - GITEA__database__USER=gitea - - GITEA__database__PASSWD=gitea - networks: - - gitea - volumes: - - ../data/gitea:/data - - /etc/timezone:/etc/timezone:ro - - /etc/localtime:/etc/localtime:ro - - /home/git/.ssh/:/data/git/.ssh - ports: - - "3030:3000" - - "2222:22" - restart: always - depends_on: - - db - - db: - image: postgres:13.4-alpine - restart: always - environment: - - POSTGRES_USER=gitea - - POSTGRES_PASSWORD=gitea - - POSTGRES_DB=gitea - volumes: - - ../data/gitea/postgres:/var/lib/postgresql/data - networks: - - gitea diff --git a/gitea/env.production b/gitea/env.production deleted file mode 100644 index 70b7682..0000000 --- a/gitea/env.production +++ /dev/null @@ -1,7 +0,0 @@ -# gitea config for keycloak integration -# only allow open id sign-in, turn off all other registrations -GITEA__openid__ENABLE_OPENID_SIGNIN=true -GITEA__openid__ENABLE_OPENID_SIGNUP=false -#GITEA__service__DISABLE_REGISTRATION=true -GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION=true -GITEA__repository__DEFAULT_BRANCH=main diff --git a/gitea/add-ssh-user b/gitea/host-setup.sh similarity index 100% rename from gitea/add-ssh-user rename to gitea/host-setup.sh diff --git a/gitea/keycloak.sh b/gitea/keycloak.sh new file mode 100755 index 0000000..dc2341b --- /dev/null +++ b/gitea/keycloak.sh @@ -0,0 +1,4 @@ +#!/bin/bash -x +# Setup the gitea client connection + +client-create gitea "$GITEA_HOSTNAME.$DOMAIN_NAME" "$GITEA_CLIENT_SECRET" &2 "gitea: ERROR $*" ; exit 1 ; } -info() { echo >&2 "gitea: $*" ; } - -DIRNAME="$(dirname $0)" -cd "$DIRNAME" - -source ../env.production || die "no top level environment" -source ./env.production || die "no local environment" - -DATA="../data/gitea" -SECRETS="$DATA/env.secrets" -INI="$DATA/gitea/conf/app.ini" - -if [ -r "$SECRETS" ]; then - docker-compose up -d || die "unable to start" - exit 0 -fi - -./add-ssh-user || die "unable to add ssh user" - -GITEA_CLIENT_SECRET="$(openssl rand -hex 32)" -GITEA_ADMIN_PASSWORD="$(openssl rand -hex 8)" - -info "creating new secrets $SECRETS" - -mkdir -p "$DATA" -cat < "$SECRETS" -# DO NOT CHECK IN -GITEA_CLIENT_SECRET=$GITEA_CLIENT_SECRET -GITEA_ADMIN_PASSWORD=$GITEA_ADMIN_PASSWORD -GITEA__server__ROOT_URL=https://$GITEA_HOSTNAME/ -GITEA__server__SSH_DOMAIN=$GITEA_HOSTNAME -GITEA__security__INSTALL_LOCK=true -GITEA__security__SECRET_KEY=$(openssl rand -hex 32) -EOF - - -docker-compose down 2>/dev/null - -../keycloak/client-delete gitea 2>/dev/null -../keycloak/client-create <&2 "*** Sleeping for setup" +sleep 30 + +echo >&2 "*** Adding OIDC login for $DOMAIN_NAME" +su -s /bin/sh git <&2 "*** Done, maybe it works?" +exit 0 diff --git a/wireguard/README.md b/wireguard/README.md new file mode 100644 index 0000000..cdabf97 --- /dev/null +++ b/wireguard/README.md @@ -0,0 +1,29 @@ +# Wireguard proxy setup + +This is for a server that is inside of a firewall or behind a NAT gateway +that doesn't have a static IP address. A cheap $6/month DigitalOcean droplet +can be created that will route *all* internet traffic to the server, allowing +it to change IP. + +* On both proxy and the server: + +``` +sudo apt install wireguard-tools net-tools +wg genkey \ +| sudo tee /etc/wireguard/wg0.key \ +| wg pubkey \ +| sudo tee /etc/wireguard/wg0.pub +sudo chmod -R go-rwx /etc/wireguard +``` + +* Copy `wireguard/wg0-proxy.conf` to `/etc/wireguard/wg0.conf` on the proxy +* On the **proxy** edit `/etc/wireguard/wg0.conf`: + * Change `${SERVER_PUBKEY}` to the public key that was output on the server + +* Copy `wireguard/wg0-server.conf` to `/etc/wireguard/wg0.conf` on the server. +* On the **server** edit `/etc/wireguard/wg0.conf`: + * Change `${PROXY_IP}` to the public IP address of the proxy (two places) + * Change `${PROXY_PUBKEY}` to the public key output on the proxy (two places) + * Change `${SERVER_GW}` to the gateway address used to reach the internet from the server + +* On both machines run `sudo wg-quick up /etc/wireguard/wg0.conf` diff --git a/wireguard/wg0-proxy.conf b/wireguard/wg0-proxy.conf new file mode 100644 index 0000000..e7bdbc5 --- /dev/null +++ b/wireguard/wg0-proxy.conf @@ -0,0 +1,33 @@ +[Interface] +Address = 192.168.4.1/24 +ListenPort = 51820 + +PostUp = wg set %i private-key /etc/wireguard/%i.key + +# Enable IP masquerading for the remote host +PostUp = echo 1 > /proc/sys/net/ipv4/ip_forward +PostUp = iptables -A FORWARD -i %i -j ACCEPT +PostUp = iptables -A FORWARD -o %i -j ACCEPT +PostUp = iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE + +# accept the wireguard connection +PostUp = iptables -t nat -A PREROUTING -i eth0 -p udp --dport 51820 -j ACCEPT + +# redirect ssh to port 23 +PostUp = iptables -t nat -A PREROUTING -i eth0 -p tcp --dport 23 -j REDIRECT --to-port 22 + +# redirect *all* traffic to the wg tunnel +PostUp = iptables -t nat -A PREROUTING -i eth0 -p all -j DNAT --to-destination 192.168.4.2 + +# Tear down the proxy +PostDown = iptables -D FORWARD -i %i -j ACCEPT +PostDown = iptables -D FORWARD -o %i -j ACCEPT +PostDown = iptables -t nat -D POSTROUTING -o eth0 -j MASQUERADE + +PostDown = iptables -t nat -D PREROUTING -i eth0 -p udp --dport 51820 -j ACCEPT +PostDown = iptables -t nat -D PREROUTING -i eth0 -p tcp --dport 23 -j REDIRECT -to-port 22 +PostDown = iptables -t nat -D PREROUTING -i eth0 -p all -j DNAT --to-destination 192.168.4.2 + +[Peer] +PublicKey = ${SERVER_PUBKEY} +AllowedIPs = 192.168.4.2/32 diff --git a/wireguard/wg0-server.conf b/wireguard/wg0-server.conf new file mode 100644 index 0000000..9e65fba --- /dev/null +++ b/wireguard/wg0-server.conf @@ -0,0 +1,28 @@ +# wg0-server.conf +# +# This is the configuration for the server hidden behind the wireguard proxy. +# It routes all internet traffic via the proxy, with the exception of traffic +# to the proxy itself. It is still accessible on the local network. +# +# When moving this to a new machine: +# * Update the PostUp route so that the proxy address has an explicit route via the local gateway +# * Update the PownDown to delete the explicit route and restore the default gw +# * Update the Peer PublicKey and Endpoint with the proxy key and address +# +[Interface] +PostUp = wg set %i private-key /etc/wireguard/%i.key +Address = 192.168.4.2/24 + +# Delete the default gateway and add an explicit route for the wireguard tunnel +PostUp = route add ${PROXY_IP} gw ${SERVER_GW} || echo "wrong route" +PostUp = route del default || echo "no default" +PostUp = route add default gw 192.168.4.1 + +PostDown = route del ${PROXY_IP} +PostDown = route add default gw ${SERVER_GW} + +[Peer] +PublicKey = ${PROXY_PUBKEY} +Endpoint = ${PROXY_IP}:51820 +AllowedIPs = 0.0.0.0/0 +PersistentKeepalive = 25