Add devigo deployment role for mini-vps production environment
- Created comprehensive devigo Ansible role with Podman Quadlet support - Deployed devigo-site container (Hugo + nginx) via systemd - Deployed devigo-decap-oauth OAuth2 proxy for Decap CMS - Integrated with Caddy reverse proxy for HTTPS Services deployed: - devigo.no (apex domain, primary) - www.devigo.no (redirects to apex) - decap.jnss.me (OAuth proxy) Key features: - REGISTRY_AUTH_FILE environment for Podman GHCR authentication - TRUSTED_ORIGINS (plural) for decapcms-oauth2 multi-origin support - JavaScript-based Decap CMS initialization (eliminates YAML MIME dependency) - nginx location block for YAML MIME type (text/yaml) - Automated deployment via GitHub Actions CI/CD - Comprehensive documentation with troubleshooting guide - Architecture decision records Fixes applied during deployment: - OAuth origin trust validation (TRUSTED_ORIGINS vs TRUSTED_ORIGIN) - MIME type handling strategy (location-specific vs server-level types block) - Decap CMS initialization method (JavaScript vs link tag) - Podman authentication for systemd services (REGISTRY_AUTH_FILE) Testing status: - ✅ MIME types verified (HTML, CSS, YAML all correct) - ✅ OAuth authentication working - ✅ Container image pulls from private GHCR - ✅ Automated deployments functional - ✅ Site fully operational at devigo.no
This commit is contained in:
25
roles/devigo/templates/devigo-decap-oauth.caddy.j2
Normal file
25
roles/devigo/templates/devigo-decap-oauth.caddy.j2
Normal file
@@ -0,0 +1,25 @@
|
||||
# Decap CMS OAuth2 Proxy
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
{{ devigo_oauth_domain }} {
|
||||
reverse_proxy 127.0.0.1:{{ devigo_oauth_container_port }}
|
||||
|
||||
# Security headers
|
||||
header {
|
||||
X-Frame-Options DENY
|
||||
X-Content-Type-Options nosniff
|
||||
Referrer-Policy strict-origin-when-cross-origin
|
||||
}
|
||||
|
||||
# Logging
|
||||
log {
|
||||
output file /var/log/caddy/devigo-decap-oauth.log {
|
||||
roll_size 100mb
|
||||
roll_keep 5
|
||||
}
|
||||
format json {
|
||||
time_format "2006-01-02T15:04:05.000Z07:00"
|
||||
}
|
||||
level INFO
|
||||
}
|
||||
}
|
||||
25
roles/devigo/templates/devigo-decap-oauth.container
Normal file
25
roles/devigo/templates/devigo-decap-oauth.container
Normal file
@@ -0,0 +1,25 @@
|
||||
[Unit]
|
||||
Description=Decap CMS OAuth2 Proxy for Devigo
|
||||
After=network-online.target
|
||||
Wants=network-online.target
|
||||
|
||||
[Container]
|
||||
Image={{ devigo_oauth_container_image }}
|
||||
ContainerName={{ devigo_oauth_container_name }}
|
||||
AutoUpdate=registry
|
||||
|
||||
# Environment file with secrets
|
||||
EnvironmentFile={{ devigo_oauth_home }}/decap-oauth.env
|
||||
|
||||
# Network
|
||||
PublishPort=127.0.0.1:{{ devigo_oauth_container_port }}:12000
|
||||
|
||||
# Security
|
||||
NoNewPrivileges=true
|
||||
|
||||
[Service]
|
||||
Restart=always
|
||||
TimeoutStartSec=900
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
10
roles/devigo/templates/devigo-decap-oauth.env.j2
Normal file
10
roles/devigo/templates/devigo-decap-oauth.env.j2
Normal file
@@ -0,0 +1,10 @@
|
||||
# Decap OAuth Environment Configuration
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
OAUTH_CLIENT_ID={{ devigo_oauth_client_id }}
|
||||
OAUTH_CLIENT_SECRET={{ devigo_oauth_client_secret }}
|
||||
SERVER_PORT=12000
|
||||
|
||||
# TRUSTED_ORIGINS must be comma-separated string (not YAML array)
|
||||
# Example: https://example.com,https://www.example.com
|
||||
TRUSTED_ORIGINS={{ devigo_oauth_trusted_origins }}
|
||||
31
roles/devigo/templates/devigo-site.container
Normal file
31
roles/devigo/templates/devigo-site.container
Normal file
@@ -0,0 +1,31 @@
|
||||
[Unit]
|
||||
Description=Devigo Website - Sales Training Company
|
||||
After=network-online.target caddy.service
|
||||
Wants=network-online.target
|
||||
Requires=caddy.service
|
||||
|
||||
[Container]
|
||||
Image=ghcr.io/jnschaffer/rustan:prod
|
||||
ContainerName=devigo-site
|
||||
AutoUpdate=registry
|
||||
Pull=newer
|
||||
|
||||
# Port mapping - publish to localhost only
|
||||
PublishPort=127.0.0.1:9080:80
|
||||
|
||||
# Security
|
||||
NoNewPrivileges=true
|
||||
|
||||
# Health check - check if nginx is responding
|
||||
HealthCmd=/usr/bin/curl -f http://localhost:80/ || exit 1
|
||||
HealthInterval=30s
|
||||
HealthTimeout=10s
|
||||
HealthRetries=3
|
||||
|
||||
[Service]
|
||||
Environment=REGISTRY_AUTH_FILE=/etc/containers/auth.json
|
||||
Restart=always
|
||||
TimeoutStartSec=900
|
||||
|
||||
[Install]
|
||||
WantedBy=default.target
|
||||
33
roles/devigo/templates/devigo.caddy.j2
Normal file
33
roles/devigo/templates/devigo.caddy.j2
Normal file
@@ -0,0 +1,33 @@
|
||||
# Devigo Website - Reverse Proxy to Containerized Site
|
||||
# Generated by Ansible - DO NOT EDIT MANUALLY
|
||||
|
||||
# Redirect www to apex (apex is primary per user preference)
|
||||
{{ devigo_www_domain }} {
|
||||
redir https://{{ devigo_domain }}{uri} permanent
|
||||
}
|
||||
|
||||
# Primary domain (apex)
|
||||
{{ devigo_domain }} {
|
||||
reverse_proxy localhost:9080
|
||||
|
||||
# Security headers
|
||||
header {
|
||||
X-Frame-Options SAMEORIGIN
|
||||
X-Content-Type-Options nosniff
|
||||
X-XSS-Protection "1; mode=block"
|
||||
Referrer-Policy strict-origin-when-cross-origin
|
||||
Permissions-Policy "geolocation=(), microphone=(), camera=()"
|
||||
}
|
||||
|
||||
# Logging
|
||||
log {
|
||||
output file /var/log/caddy/devigo.log {
|
||||
roll_size 100mb
|
||||
roll_keep 5
|
||||
}
|
||||
format json {
|
||||
time_format "2006-01-02T15:04:05.000Z07:00"
|
||||
}
|
||||
level INFO
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user