Skip to content
Open
Show file tree
Hide file tree
Changes from 5 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
1859682
feat: add TLS configuration for proxy service in workspace.yml
marcomc Jun 17, 2026
c660f3d
feat: update proxy service configurations to use dynamic domain varia…
marcomc Jun 17, 2026
830868e
feat: simplify enable function in init scripts and add TLS configurat…
marcomc Jun 17, 2026
f82d195
feat: add tests for global proxy domain configuration and overrides
marcomc Jun 17, 2026
ee3ff1a
feat: add documentation for custom global proxy domain configuration
marcomc Jun 17, 2026
17dd727
feat: remove unused environment variables from proxy service command …
marcomc Jun 17, 2026
f3fa4b4
feat: add descriptions for logger and tracing service commands in glo…
marcomc Jun 17, 2026
bd2ecb2
feat: enhance create command with description and exec block formatting
marcomc Jun 17, 2026
29bcfa4
feat: update attribute source handling to use latest source and highe…
marcomc Jun 17, 2026
97804ec
feat: update offsetGet method to return mixed type and add test for a…
marcomc Jun 17, 2026
6582f60
feat: add MY127WS_PROXY_DOMAIN export in service init scripts and tes…
marcomc Jun 17, 2026
0241a4e
feat: add tracing service environment file to files-bin in box.json
marcomc Jun 17, 2026
e13be5a
feat: enhance global proxy configuration with environment variable su…
marcomc Jun 17, 2026
9a4bf43
feat: add TLS validation functions to ensure certificate and key file…
marcomc Jun 17, 2026
cac212c
feat: enhance global proxy service tests with TLS validation and erro…
marcomc Jun 17, 2026
3c7ac04
feat: update documentation for proxy configuration with HTTPS require…
marcomc Jun 17, 2026
283b292
feat: implement proxy environment population and update service initi…
marcomc Jun 18, 2026
adeb1b3
feat: update init script to use dynamic workspace binary reference fo…
marcomc Jun 18, 2026
1b9e48b
feat: enhance workspace binary reference handling and update proxy en…
marcomc Jun 18, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions config/workspace/global.yml
Original file line number Diff line number Diff line change
@@ -1,23 +1,37 @@

command('global service logger (enable|disable)', 'global service logger'): |
#!bash|=
ws-service logger ={input.command(4)}
command('global service logger (enable|disable)', 'global service logger'):
env:
MY127WS_PROXY_DOMAIN: = @('global.service.proxy.domain')
exec: |
#!bash|=
ws-service logger ={input.command(4)}

command('global service mail (enable|disable)', 'global service mail'):
description: Actions for mailhog (mail.my127.site)
description: Actions for mailhog
env:
MY127WS_PROXY_DOMAIN: = @('global.service.proxy.domain')
exec: |
#!bash|=
ws-service mail ={input.command(4)}

command('global service proxy (enable|disable|restart)', 'global service proxy'):
description: Actions for Traefik proxy (my127.site)
description: Actions for Traefik proxy
env:
MY127WS_PROXY_DOMAIN: = @('global.service.proxy.domain')
MY127WS_PROXY_HTTPS_CRT: = @('global.service.proxy.https.crt')
MY127WS_PROXY_HTTPS_KEY: = @('global.service.proxy.https.key')
MY127WS_PROXY_HTTPS_CRT_FILE: = @('global.service.proxy.https.crt_file')
MY127WS_PROXY_HTTPS_KEY_FILE: = @('global.service.proxy.https.key_file')
exec: |
#!bash|=
ws-service proxy ={input.command(4)}

command('global service tracing (start|stop|restart)', 'global service tracing'): |
#!bash|=
ws-service tracing ={input.command(4)}
command('global service tracing (start|stop|restart)', 'global service tracing'):
env:
MY127WS_PROXY_DOMAIN: = @('global.service.proxy.domain')
exec: |
#!bash|=
ws-service tracing ={input.command(4)}

command('global service', 'global service'):
description: Perform an action (start/stop etc.) on a global service
Expand Down
22 changes: 20 additions & 2 deletions docs/cheatsheet.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,24 @@ You need only to restart the Traefik proxy service:
ws global service proxy restart
```

## Custom proxy domain

See [Custom Global Proxy Domain](custom-proxy-domain.md) for the full setup.

Minimal global config file:

```text
~/.config/my127/workspace/proxy.yml
```

```yaml
attribute('global.service.proxy.domain'): dev.example.test
attribute('global.service.proxy.https.crt'): https://example.test/dev.example.test.crt
attribute('global.service.proxy.https.key'): https://example.test/dev.example.test.key
```

Restart the proxy after changing these values.

## How-to receive email

The email service is not running by default. It can be started with:
Expand All @@ -18,6 +36,6 @@ The email service is not running by default. It can be started with:
ws global service mail enable
```

This will allow email to be viewed at `https://mail.my127.site/`
This will allow email to be viewed at `https://mail.<proxy-domain>/`

This will collect email sent from any server through native `sendmail`.
This will collect email sent from any server through native `sendmail`.
231 changes: 231 additions & 0 deletions docs/custom-proxy-domain.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,231 @@
# Custom Global Proxy Domain

Workspace uses `my127.site` by default for local HTTPS hostnames. You can
replace that single Global Proxy domain with another domain by adding a global
Workspace config file on the developer machine.

This feature supports one proxy domain at a time. It does not register multiple
domains.

## Contents

- [How it fits together](#how-it-fits-together)
- [Create the proxy config file](#create-the-proxy-config-file)
- [Host the certificate files](#host-the-certificate-files)
- [Configure DNS](#configure-dns)
- [Apply the change](#apply-the-change)
- [Use the domain in a project](#use-the-domain-in-a-project)
- [Renew certificates](#renew-certificates)

## How it fits together

Workspace automatically loads global config files from:

```text
~/.config/my127/workspace/*.yml
```

Use `proxy.yml` for the proxy override:

```text
~/.config/my127/workspace/proxy.yml
```

`proxy.yml` is a normal Workspace global config file. It is not fetched from a
remote URL and it is not managed by a Workspace import command.

```mermaid
flowchart LR
configFile["~/.config/my127/workspace/proxy.yml"]
attributes["global.service.proxy.* attributes"]
commands["ws global service proxy restart"]
init["home/service/proxy/init.sh"]
compose["docker-compose labels"]
tlsFiles["traefik/root/tls/<cert files>"]
tlsConfig["traefik/root/config/tls.yaml"]
traefik["Single Traefik Global Proxy"]

configFile --> attributes
attributes --> commands
commands --> init
init --> compose
init --> tlsFiles
init --> tlsConfig
compose --> traefik
tlsFiles --> traefik
tlsConfig --> traefik
```

The configured values are passed to Docker Compose as environment variables at
runtime. The source of truth remains the global Workspace config file.

## Create the proxy config file

Minimal `~/.config/my127/workspace/proxy.yml`:

```yaml
attribute('global.service.proxy.domain'): dev.example.test
attribute('global.service.proxy.https.crt'): https://proxy-config.example.internal/certs/dev.example.test/fullchain.pem
attribute('global.service.proxy.https.key'): https://proxy-config.example.internal/certs/dev.example.test/privkey.pem
```

The local certificate filenames default to:

```text
<domain>.crt
<domain>.key
```

For the example above, Workspace writes:

```text
traefik/root/tls/dev.example.test.crt
traefik/root/tls/dev.example.test.key
```

Override the local filenames only when needed:

```yaml
attribute('global.service.proxy.https.crt_file'): proxy.crt
attribute('global.service.proxy.https.key_file'): proxy.key
```

Full example:

```yaml
attribute('global.service.proxy.domain'): dev.example.test
attribute('global.service.proxy.https.crt'): https://proxy-config.example.internal/certs/dev.example.test/fullchain.pem
attribute('global.service.proxy.https.key'): https://proxy-config.example.internal/certs/dev.example.test/privkey.pem
attribute('global.service.proxy.https.crt_file'): dev.example.test.crt
attribute('global.service.proxy.https.key_file'): dev.example.test.key
```

## Host the certificate files

The certificate and key URLs must be reachable from each developer machine when
`ws global service proxy restart` runs.

The files do not need to live beside `proxy.yml`. `proxy.yml` only stores the
URLs where Workspace can download them.

Suggested hosted structure:

```text
proxy-config/
└── certs/
└── dev.example.test/
├── fullchain.pem
└── privkey.pem
```

GitHub raw URLs work only for public repositories because Workspace does not
authenticate to GitHub. Use public GitHub raw URLs only for disposable test
certificates.

Example public GitHub repository structure:

```text
workspace-proxy-certs/
└── certs/
└── dev.example.test/
├── fullchain.pem
└── privkey.pem
```

Example `proxy.yml` using GitHub raw URLs:

```yaml
attribute('global.service.proxy.domain'): dev.example.test
attribute('global.service.proxy.https.crt'): https://raw.githubusercontent.com/my-org/workspace-proxy-certs/main/certs/dev.example.test/fullchain.pem
attribute('global.service.proxy.https.key'): https://raw.githubusercontent.com/my-org/workspace-proxy-certs/main/certs/dev.example.test/privkey.pem
```

For organisation/private certificates, use an internal HTTP(S) location that is
reachable from developer machines, such as a private website available on the
company network or VPN.

The certificate must cover the configured domain and the subdomains used by
projects and global services. For `dev.example.test`, the certificate should
cover:

```text
dev.example.test
*.dev.example.test
```

The wildcard covers project hosts and global service hosts such as:

```text
mail.dev.example.test
kibana.dev.example.test
tracing.dev.example.test
```

## Configure DNS

The configured domain and wildcard subdomains must resolve to the developer
machine running the Workspace Global Proxy.

For local development, common options are:

- public DNS records that point the domain and wildcard to `127.0.0.1`;
- private DNS records available only on the organisation network;
- local DNS tools such as Pi-hole, dnsmasq, or `/etc/hosts` for individual
hostnames.

Wildcard support is recommended because project hostnames are usually generated
under the proxy domain.

## Apply the change

After creating or changing `proxy.yml`, restart the proxy:

```bash
ws global service proxy restart
```

The restart downloads the certificate and key, renders Traefik TLS config, and
recreates the proxy container.

If mail, logger, or tracing are already running, restart those services too so
their Docker labels use the new hostnames:

```bash
ws global service mail enable
ws global service logger enable
ws global service tracing restart
```

## Use the domain in a project

Projects should use the same proxy domain suffix configured globally. For
example:

```yaml
attributes:
domain: dev.example.test
```

Project hostnames should then be under that suffix, such as:

```text
my-project.dev.example.test
```

This simplified proxy configuration supports one certificate/domain set at a
time. If the proxy is configured for `dev.example.test`, projects still using
`my127.site` may no longer match the active certificate.

## Renew certificates

When a certificate is renewed, keep the hosted certificate URLs stable and
replace the file contents at those URLs.

Then run:

```bash
ws global service proxy restart
```

You only need to edit `proxy.yml` when the domain, certificate URL, key URL, or
local filename changes.
2 changes: 1 addition & 1 deletion home/service/logger/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ services:
- elasticsearch
labels:
- traefik.enable=true
- traefik.http.routers.kibana.rule=Host(`kibana.my127.site`)
- traefik.http.routers.kibana.rule=Host(`kibana.${MY127WS_PROXY_DOMAIN:-my127.site}`)
- traefik.http.services.kibana.loadbalancer.server.port=5601
- traefik.docker.network=${TRAEFIK_NETWORK}
networks:
Expand Down
8 changes: 2 additions & 6 deletions home/service/logger/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,8 @@ main()

enable()
{
if [ ! -f .flag-built ]; then
run docker-compose -p my127ws-logger up -d --build
touch .flag-built
else
run docker-compose -p my127ws-logger start
fi
run docker-compose -p my127ws-logger up -d --build
touch .flag-built

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The proxy domain is now part of the Docker Compose labels.

With the previous flow, after the first build enable only ran docker-compose start. That starts the existing container as-is, so label changes are not applied.

If global.service.proxy.domain changes, mail/logger could otherwise keep stale labels such as mail.my127.site or kibana.my127.site.

Using docker-compose up -d --build keeps the command idempotent while allowing Compose to recreate the container when the labels/config changed.

}

disable()
Expand Down
2 changes: 1 addition & 1 deletion home/service/mail/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ services:
restart: unless-stopped
labels:
- traefik.enable=true
- traefik.http.routers.mail.rule=Host(`mail.my127.site`)
- traefik.http.routers.mail.rule=Host(`mail.${MY127WS_PROXY_DOMAIN:-my127.site}`)
- traefik.http.services.mail.loadbalancer.server.port=8025
networks:
- private
Expand Down
8 changes: 2 additions & 6 deletions home/service/mail/init.sh
Original file line number Diff line number Diff line change
Expand Up @@ -21,12 +21,8 @@ main()

enable()
{
if [ ! -f .flag-built ]; then
run docker-compose -p my127ws-mail up -d --build
touch .flag-built
else
run docker-compose -p my127ws-mail start
fi
run docker-compose -p my127ws-mail up -d --build
touch .flag-built
}

disable()
Expand Down
2 changes: 1 addition & 1 deletion home/service/proxy/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ services:
- 443:443/udp
labels:
- traefik.enable=true
- traefik.http.routers.traefik.rule=Host(`my127.site`)
- traefik.http.routers.traefik.rule=Host(`${MY127WS_PROXY_DOMAIN:-my127.site}`)
- traefik.http.services.traefik.loadbalancer.server.port=8080
- co.elastic.logs/module=traefik
volumes:
Expand Down
Loading
Loading