Updated code to configure Forgejo to have two DNS names, one for git and for ssh.
Some checks failed
deploy / deploy (push) Has been cancelled
Some checks failed
deploy / deploy (push) Has been cancelled
This commit is contained in:
parent
1250c9cef6
commit
d59f463d3d
9 changed files with 97 additions and 10 deletions
|
|
@ -771,6 +771,14 @@ the native install needs, `terraform apply -target=module.forgejo`,
|
||||||
Ansible deliberately does not do — moving repository data, and the DNS/SSH-port
|
Ansible deliberately does not do — moving repository data, and the DNS/SSH-port
|
||||||
cutover.
|
cutover.
|
||||||
|
|
||||||
|
Note Forgejo needs **two** DNS names, not one: `FORGEJO_DOMAIN` for the web
|
||||||
|
side, pointing at whatever terminates HTTPS in front of it, and
|
||||||
|
`FORGEJO_SSH_DOMAIN` for git-over-SSH, pointing at the container itself. SSH
|
||||||
|
has no SNI, so a reverse proxy can't route it by hostname the way it routes
|
||||||
|
HTTP — the split is forced by the protocol. See
|
||||||
|
`src/forgejo/ansible/proxmox/README.md` for the alternative (a layer-4 TCP
|
||||||
|
proxy) and why it isn't used here.
|
||||||
|
|
||||||
## Deploying one platform, one host, one stack
|
## Deploying one platform, one host, one stack
|
||||||
|
|
||||||
`playbooks/deploy.yml` runs everything; `playbooks/unraid.yml`,
|
`playbooks/deploy.yml` runs everything; `playbooks/unraid.yml`,
|
||||||
|
|
|
||||||
|
|
@ -18,8 +18,14 @@
|
||||||
# off nas2, which is no longer a machine that can be read from.
|
# off nas2, which is no longer a machine that can be read from.
|
||||||
#
|
#
|
||||||
# Also note SSH clone URLs move from port 2222 to 22 (see FORGEJO_SSH_PORT in
|
# Also note SSH clone URLs move from port 2222 to 22 (see FORGEJO_SSH_PORT in
|
||||||
# src/forgejo/ansible/proxmox/vars.yml): existing remotes need editing, and
|
# src/forgejo/ansible/proxmox/vars.yml): existing remotes need editing.
|
||||||
# git.turtlesystems.uk has to resolve to this container.
|
#
|
||||||
|
# They also move to a different *hostname*. HTTP for git.turtlesystems.uk is
|
||||||
|
# proxied by Caddy, which is a different machine and has no sshd, so SSH is
|
||||||
|
# advertised as src.turtlesystems.uk instead (FORGEJO_SSH_DOMAIN, same file) —
|
||||||
|
# and it is that name, not the web one, that has to resolve to `ansible_host`
|
||||||
|
# below. SSH has no SNI, so this split is forced by the protocol rather than
|
||||||
|
# being a Caddy shortcoming; the reasoning is in vars.yml.
|
||||||
|
|
||||||
# The address Terraform assigns this guest (build/config/terraform/main.tf).
|
# The address Terraform assigns this guest (build/config/terraform/main.tf).
|
||||||
# Pinned here rather than left to DNS: the API-backed dynamic inventory
|
# Pinned here rather than left to DNS: the API-backed dynamic inventory
|
||||||
|
|
|
||||||
|
|
@ -192,11 +192,25 @@ gives back every file and no issues, pull requests, users or permissions.
|
||||||
|
|
||||||
Last, once the above is verified:
|
Last, once the above is verified:
|
||||||
|
|
||||||
- Point `git.turtlesystems.uk` at this container.
|
- Point `git.turtlesystems.uk` at whatever terminates HTTPS for it — the Caddy
|
||||||
- **SSH clone URLs move from port 2222 to 22.** The Unraid stack published
|
reverse proxy at 192.168.50.51, which proxies through to this container's
|
||||||
2222 to dodge the host's own sshd; this container has its own IP and uses
|
`FORGEJO_HTTP_PORT`.
|
||||||
its own sshd, with Forgejo managing the `git` user's `authorized_keys`.
|
- Point `src.turtlesystems.uk` at this container (192.168.50.52). This is the
|
||||||
Every existing remote needs editing — there is no redirect for this.
|
name in `FORGEJO_SSH_DOMAIN`, and the one SSH clone URLs use.
|
||||||
|
- **SSH clone URLs move from port 2222 to 22, and onto their own hostname.**
|
||||||
|
The Unraid stack published 2222 to dodge the host's own sshd; this container
|
||||||
|
has its own IP and uses its own sshd, with Forgejo managing the `git` user's
|
||||||
|
`authorized_keys`. Every existing remote needs editing — there is no
|
||||||
|
redirect for this.
|
||||||
|
|
||||||
|
The two hostnames are not redundancy. An SSH client sends a version banner
|
||||||
|
and nothing identifying the host it meant — there is no equivalent of TLS
|
||||||
|
SNI — so a reverse proxy cannot route SSH by name the way it routes HTTP.
|
||||||
|
The web name therefore has to point at the proxy and the SSH name at
|
||||||
|
Forgejo. Collapsing them into one would mean putting a layer-4 TCP proxy on
|
||||||
|
the proxy's port 22 (Caddy can, via the third-party `caddy-l4` module, at
|
||||||
|
the cost of a custom binary and of losing client IPs on SSH), not
|
||||||
|
configuring the hostname more cleverly.
|
||||||
- The Forgejo Actions runner registration is tied to the instance. Re-register
|
- The Forgejo Actions runner registration is tied to the instance. Re-register
|
||||||
it against the new host, or CI stops running (`.forgejo/workflows/`).
|
it against the new host, or CI stops running (`.forgejo/workflows/`).
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,6 +79,21 @@ editing `FORGEJO_RELEASE` and redeploying.
|
||||||
the `git` user's `authorized_keys` rather than running its own server. This
|
the `git` user's `authorized_keys` rather than running its own server. This
|
||||||
changes the SSH clone URLs Forgejo advertises, so existing remotes need
|
changes the SSH clone URLs Forgejo advertises, so existing remotes need
|
||||||
updating after a migration.
|
updating after a migration.
|
||||||
|
- **SSH is on its own hostname** (`FORGEJO_SSH_DOMAIN` =
|
||||||
|
`src.turtlesystems.uk`), separate from the web one (`FORGEJO_DOMAIN` =
|
||||||
|
`git.turtlesystems.uk`, which resolves to the Caddy reverse proxy). Not a
|
||||||
|
redundancy and not a Caddy limitation: SSH has no SNI — the client sends a
|
||||||
|
version banner and nothing naming the host it meant — so no reverse proxy
|
||||||
|
can route SSH by hostname the way it routes HTTP. The web name has to point
|
||||||
|
at whatever terminates TLS and the SSH name at whatever runs sshd, and here
|
||||||
|
those are different machines. One name is possible only by putting a
|
||||||
|
layer-4 TCP proxy on the proxy's port 22 (Caddy's third-party `caddy-l4`
|
||||||
|
module does this) and accepting a custom Caddy build plus every SSH
|
||||||
|
connection appearing to originate from the proxy.
|
||||||
|
|
||||||
|
Both names must therefore exist in DNS, and the failure mode of getting
|
||||||
|
this wrong is quiet: web logins work, and only `git push` breaks, with a
|
||||||
|
connection refused against a host that has no sshd.
|
||||||
- **`INSTALL_LOCK = true`.** `app.ini` is rendered in full from Vault, so the
|
- **`INSTALL_LOCK = true`.** `app.ini` is rendered in full from Vault, so the
|
||||||
web installer is skipped entirely. Nothing is left for Forgejo to generate
|
web installer is skipped entirely. Nothing is left for Forgejo to generate
|
||||||
on first boot — which is why `LFS_JWT_SECRET` has to exist in Vault here
|
on first boot — which is why `LFS_JWT_SECRET` has to exist in Vault here
|
||||||
|
|
|
||||||
|
|
@ -28,8 +28,14 @@ HTTP_PORT = {{ app_config.FORGEJO_HTTP_PORT }}
|
||||||
APP_DATA_PATH = {{ app_config.FORGEJO_DATA_PATH }}
|
APP_DATA_PATH = {{ app_config.FORGEJO_DATA_PATH }}
|
||||||
{# The container's own sshd serves git over SSH, so Forgejo only advertises
|
{# The container's own sshd serves git over SSH, so Forgejo only advertises
|
||||||
the address and manages the git user's authorized_keys. On Unraid this was
|
the address and manages the git user's authorized_keys. On Unraid this was
|
||||||
Forgejo's built-in server behind a published Docker port. #}
|
Forgejo's built-in server behind a published Docker port.
|
||||||
SSH_DOMAIN = {{ app_config.FORGEJO_DOMAIN }}
|
|
||||||
|
FORGEJO_SSH_DOMAIN, not FORGEJO_DOMAIN: SSH reaches this container
|
||||||
|
directly while HTTP goes through a reverse proxy, so the two names resolve
|
||||||
|
to different machines. Rendering the web domain here advertises clone URLs
|
||||||
|
pointing at the proxy, which has no sshd — see ../vars.yml for why the
|
||||||
|
protocol leaves no other option. #}
|
||||||
|
SSH_DOMAIN = {{ app_config.FORGEJO_SSH_DOMAIN }}
|
||||||
SSH_PORT = {{ app_config.FORGEJO_SSH_PORT }}
|
SSH_PORT = {{ app_config.FORGEJO_SSH_PORT }}
|
||||||
START_SSH_SERVER = false
|
START_SSH_SERVER = false
|
||||||
DISABLE_SSH = false
|
DISABLE_SSH = false
|
||||||
|
|
|
||||||
|
|
@ -27,6 +27,25 @@ env_defaults:
|
||||||
# SSH clone URLs Forgejo advertises — see README.md in this directory.
|
# SSH clone URLs Forgejo advertises — see README.md in this directory.
|
||||||
FORGEJO_SSH_PORT: "22"
|
FORGEJO_SSH_PORT: "22"
|
||||||
|
|
||||||
|
# Git over SSH lands on this container directly; the web side does not. HTTP
|
||||||
|
# is proxied by Caddy at 192.168.50.51, which is what git.turtlesystems.uk
|
||||||
|
# (FORGEJO_DOMAIN) resolves to — and Caddy speaks HTTP, so port 22 there is
|
||||||
|
# closed. Pointing the SSH clone URLs at the web domain therefore advertises
|
||||||
|
# a host with no sshd on it, which is exactly what this override exists to
|
||||||
|
# avoid.
|
||||||
|
#
|
||||||
|
# Splitting the names is not a workaround for a Caddy limitation; it is
|
||||||
|
# forced by the protocol. An SSH client sends a version banner and nothing
|
||||||
|
# else — no equivalent of TLS SNI — so no proxy can tell which backend a
|
||||||
|
# connection was meant for. The alternatives are a layer-4 TCP proxy on
|
||||||
|
# port 22 (Caddy can do this via the third-party `caddy-l4` module, at the
|
||||||
|
# cost of a custom binary and of every SSH connection appearing to come from
|
||||||
|
# the proxy's address) or giving Forgejo its own name, as here.
|
||||||
|
#
|
||||||
|
# Keep in step with the A record: src.turtlesystems.uk must resolve to this
|
||||||
|
# container's `ansible_host` in host_vars/forgejo.yml (192.168.50.52).
|
||||||
|
FORGEJO_SSH_DOMAIN: src.turtlesystems.uk
|
||||||
|
|
||||||
# No `unraid_shared` Docker network here to resolve `shared-postgres`
|
# No `unraid_shared` Docker network here to resolve `shared-postgres`
|
||||||
# through, so the shared Postgres is reached over the LAN, at the address of
|
# through, so the shared Postgres is reached over the LAN, at the address of
|
||||||
# the LXC running it. Keep in step with `ip_address` on the `postgres`
|
# the LXC running it. Keep in step with `ip_address` on the `postgres`
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,9 @@ FORGEJO_HTTP_PORT=3000
|
||||||
FORGEJO_SSH_PORT=2222
|
FORGEJO_SSH_PORT=2222
|
||||||
FORGEJO_DOMAIN=git.example.internal
|
FORGEJO_DOMAIN=git.example.internal
|
||||||
FORGEJO_ROOT_URL=http://git.example.internal:3000/
|
FORGEJO_ROOT_URL=http://git.example.internal:3000/
|
||||||
|
# The host SSH clone URLs point at. Same as FORGEJO_DOMAIN unless a reverse
|
||||||
|
# proxy fronts the web side, in which case that name has no sshd behind it.
|
||||||
|
FORGEJO_SSH_DOMAIN=git.example.internal
|
||||||
DB_HOST=shared-postgres
|
DB_HOST=shared-postgres
|
||||||
DB_NAME=forgejo
|
DB_NAME=forgejo
|
||||||
DB_USER=forgejo
|
DB_USER=forgejo
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,12 @@ services:
|
||||||
FORGEJO__database__PASSWD: ${DB_PASSWORD}
|
FORGEJO__database__PASSWD: ${DB_PASSWORD}
|
||||||
FORGEJO__server__DOMAIN: ${FORGEJO_DOMAIN}
|
FORGEJO__server__DOMAIN: ${FORGEJO_DOMAIN}
|
||||||
FORGEJO__server__ROOT_URL: ${FORGEJO_ROOT_URL}
|
FORGEJO__server__ROOT_URL: ${FORGEJO_ROOT_URL}
|
||||||
FORGEJO__server__SSH_DOMAIN: ${FORGEJO_DOMAIN}
|
# Its own variable rather than ${FORGEJO_DOMAIN}: the SSH clone URLs need
|
||||||
|
# a name that resolves to whatever is actually listening for SSH, which
|
||||||
|
# is not the web domain wherever a reverse proxy terminates HTTP. Equal
|
||||||
|
# to FORGEJO_DOMAIN by default in ../../common/vars.yml, so this is a
|
||||||
|
# no-op until a platform overrides it.
|
||||||
|
FORGEJO__server__SSH_DOMAIN: ${FORGEJO_SSH_DOMAIN}
|
||||||
FORGEJO__server__SSH_PORT: ${FORGEJO_SSH_PORT}
|
FORGEJO__server__SSH_PORT: ${FORGEJO_SSH_PORT}
|
||||||
# Fixed rather than left to be auto-generated, so recreating the
|
# Fixed rather than left to be auto-generated, so recreating the
|
||||||
# container from a fresh volume doesn't invalidate sessions/tokens.
|
# container from a fresh volume doesn't invalidate sessions/tokens.
|
||||||
|
|
|
||||||
|
|
@ -9,6 +9,17 @@ env_defaults:
|
||||||
FORGEJO_SSH_PORT: "2222"
|
FORGEJO_SSH_PORT: "2222"
|
||||||
FORGEJO_DOMAIN: git.turtlesystems.uk
|
FORGEJO_DOMAIN: git.turtlesystems.uk
|
||||||
FORGEJO_ROOT_URL: "https://git.turtlesystems.uk"
|
FORGEJO_ROOT_URL: "https://git.turtlesystems.uk"
|
||||||
|
|
||||||
|
# The hostname Forgejo puts in the SSH clone URLs it advertises, kept
|
||||||
|
# separate from FORGEJO_DOMAIN because the two need not resolve to the same
|
||||||
|
# machine. SSH carries no hostname in its handshake — there is no SNI — so a
|
||||||
|
# reverse proxy cannot route it by name the way it routes HTTP. A deployment
|
||||||
|
# that terminates TLS on a proxy in front of Forgejo therefore has the web
|
||||||
|
# domain pointing at the proxy and the SSH domain pointing at Forgejo
|
||||||
|
# itself. Defaulted to FORGEJO_DOMAIN here, which is correct whenever
|
||||||
|
# nothing sits in front; the platform that needs them to differ overrides it
|
||||||
|
# (see ../ansible/proxmox/vars.yml).
|
||||||
|
FORGEJO_SSH_DOMAIN: git.turtlesystems.uk
|
||||||
DB_NAME: forgejo
|
DB_NAME: forgejo
|
||||||
DB_USER: forgejo
|
DB_USER: forgejo
|
||||||
# DB_PASSWORD, SECRET_KEY, INTERNAL_TOKEN, JWT_SECRET are secrets — sourced
|
# DB_PASSWORD, SECRET_KEY, INTERNAL_TOKEN, JWT_SECRET are secrets — sourced
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue