m2p v3 Migration Guide
This guide documents breaking changes in m2p version 3 and how to migrate your mpy_meta_config from v2.
Breaking Changes
1. expose_publicly Replaced by public_exposure
The boolean expose_publicly field has been replaced by a Selection field public_exposure that specifies how the route is exposed publicly.
v2 (deprecated):
v3 (required):
2. public_exposure Values
| Value | Description | TLS Strategy |
|---|---|---|
| (empty/omit) | Private route only (default) | Let's Encrypt via private domain |
mpy_traefik |
Public via cluster's Traefik | Let's Encrypt via public domain |
proxied |
Public via external proxy (Cloudflare, etc.) | Self-signed cert (proxy terminates TLS) |
3. Migration Table
| v2 Config | v3 Equivalent |
|---|---|
expose_publicly: true |
public_exposure: mpy_traefik |
expose_publicly: false |
(remove line or omit field) |
| (field absent) | (no change needed) |
4. Debug Config Changes
The same change applies to debug_config:
v2:
v3:
When to Use Each Option
public_exposure: mpy_traefik
- Direct public access via cluster's Traefik load balancer
- Automatic Let's Encrypt certificate for public domain
- DNS record points directly to cluster IP
- Use case: Production apps exposed to internet with full SSL/TLS termination at Traefik
public_exposure: proxied
- Public access via external proxy (Cloudflare, CDN, etc.)
- Self-signed certificate in cluster (proxy terminates TLS)
- DNS record points to proxy, proxy forwards to cluster
- Use case: Apps behind CDN, WAF, or DDoS protection
No public_exposure (private only)
- Only accessible via private DNS domain
- Let's Encrypt certificate for private domain
- Use case: Internal services, dev/staging environments
Complete Example
mpy_meta_config:
parts:
# Public API with direct Traefik access
api:
type: server
public_exposure: mpy_traefik
routes:
- name: main
pathPrefix: PathPrefix(`/`)
port_name: http
deployment:
docker_image: "myapp:v1"
ports:
- name: http
port: 8080
# Public frontend behind Cloudflare
frontend:
type: server
public_exposure: proxied
routes:
- name: main
pathPrefix: PathPrefix(`/`)
port_name: http
deployment:
docker_image: "myapp-frontend:v1"
ports:
- name: http
port: 3000
# Internal admin panel (no public exposure)
admin:
type: server
# No public_exposure = private only
routes:
- name: main
pathPrefix: PathPrefix(`/`)
port_name: http
middlewares:
ipwhitelist: true
deployment:
docker_image: "myapp-admin:v1"
ports:
- name: http
port: 8080
Prerequisites for Public Exposure
For public_exposure to work, the following must be configured on the Release:
- Public DNS Domain (
public_dns_domain_id) - Public Hostname Generator (
public_hostname_generator_id)
These are typically inherited from the Package Profile or set manually on the Release.
TLS Certificate Management
Private Routes (no public_exposure)
- Uses
letsencrypt-issuer(existing behavior) - Certificate stored in
{release_key}-{part_name}-certSecret
mpy_traefik Routes
- Uses new
letsencrypt-issuer-publicissuer - Certificate stored in
{release_key}-{part_name}-public-certSecret - Requires
tls.public_dns_domainconfiguration in values
proxied Routes
- Uses Traefik's auto-generated self-signed certificate (
tls: {}) - External proxy (Cloudflare, etc.) handles public TLS termination
Sunray Zero Trust Authentication
Sunray is a Zero Trust authentication system using Traefik's ForwardAuth middleware. It intercepts HTTP requests and validates them through a Sunray Worker service before forwarding to your application.
Prerequisites
For Sunray to work, the following must be configured:
- Cluster Level:
default_sunray_worker_release_idpointing to a deployed Sunray Worker - Release Level: Inherits from cluster automatically, or configure
sunray_worker_release_idmanually
Verify Sunray is available by checking that sunray.available: true appears in your rendered values.
enable_sunray Configuration
Add enable_sunray at the part level (not inside routes or middlewares):
| Value | Private Route | Public Route | Use Case |
|---|---|---|---|
all |
Enabled | Enabled | Full protection on all routes |
public |
Disabled | Enabled | Protect only public-facing routes |
| (omit) | Disabled | Disabled | No Sunray protection |
Part-Level Example
mpy_meta_config:
parts:
gui:
type: server
enable_sunray: public # Sunray on public routes only
public_exposure: mpy_traefik # Required for public routes
routes:
- name: main
pathPrefix: PathPrefix(`/`)
port_name: http
middlewares:
ipwhitelist: true # Can combine with other middlewares
# ...
Debug Config with Sunray
Protect your code-server debug endpoint with Sunray:
debug_mode_available: codr
debug_config:
debug_fqdn_prefix: codr-
enable_sunray: all # Protect debug access
public_exposure: mpy_traefik # Optional: expose debug publicly
command: [/usr/bin/code-server]
args: [--bind-addr=0.0.0.0:8765, --auth=password]
Complete Example (Odoo 18 with Sunray)
mpy_meta_config:
parts:
gui:
type: server
dashboard_name: Odoo GUI / API
enable_sunray: public # Sunray on public routes
public_exposure: mpy_traefik
deployment:
command: [ 'bin/odoo-ikb' ]
args:
- --max-cron-threads=0
- --workers=4
ports:
- name: odoo
port: 8069
- name: gevent
port: 8072
- name: codr
port: 8765
debug_mode: true
routes:
- name: gui
pathPrefix: PathPrefix(`/`)
port_name: odoo
middlewares:
ipwhitelist: true
- name: longpolling
pathPrefix: PathPrefix(`/websocket`) || PathPrefix(`/longpolling`)
port_name: gevent
middlewares:
ipwhitelist: true
debug_mode_available: codr
debug_config:
debug_fqdn_prefix: codr-
enable_sunray: all # Full Sunray on debug
command: [/usr/bin/code-server]
args: [--bind-addr=0.0.0.0:8765, --auth=password]
After Modifying Parts Config
- Click "Sync 'Parts Config.'" on the Installed Package
- Network Routes will be updated with
enable_middleware_sunrayflags - Optionally adjust the toggle manually in the Network tab
Important Notes
- The
middlewares.sunray: truesyntax inside routes is NOT supported - Only use
enable_sunrayat the part level or insidedebug_config - Sunray middleware is only applied when both:
enable_sunrayis configured in Parts Configsunray.available: truein the cluster configuration
Validation
m2p v3 will fail with a clear error if the chart version requires v3 features:
Update your mpy_meta_config to use public_exposure instead of expose_publicly.
Troubleshooting
Certificate not generated for public route
- Verify
public_exposure: mpy_traefikis set (notproxied) - Check
tls.public_dns_domain.certmanager_solver_nameis configured in values - Verify
letsencrypt-issuer-publicIssuer exists:kubectl get issuer -n <namespace>
DNS record not created
- Verify
manage_public_dns_recordsis enabled on the Release - Check
public_dns_domain_idandpublic_hostname_generator_idare set - Run "Setup DNS Records" button to create records
Route not accessible publicly
- Verify LoadBalancer has external IP:
kubectl get svc -n <namespace> - Check IngressRoute exists:
kubectl get ingressroute -n <namespace> - Verify DNS resolution points to correct IP