build-container / build (push) Successful in 2m42s
- docker-compose: roundcube service with inline config (Gmail/iCloud/Yahoo presets, framing allowed, persistent key); only reachable through the hub - hub passes /webmail/ through to Roundcube behind the passkey sign-in; Microsoft's sign-in page opens in the whole window and returns to the Mail tab - M365_* settings add 'Login with Microsoft 365' (README has the Entra app registration steps) - Side menu collapses to icons or hides completely (remembered per device, Ctrl/Cmd+B) - tools/webmail-test.js Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
99 lines
5.7 KiB
YAML
99 lines
5.7 KiB
YAML
services:
|
|
hub:
|
|
image: git.necloud.us/nate/hub:latest # built by the Gitea workflow; `docker compose build` builds locally instead
|
|
build: .
|
|
restart: unless-stopped
|
|
# The container looks names up through these. If necloud.us only exists on your home/LAN DNS
|
|
# (Pi-hole, router, AdGuard...), set DNS_1 to that server's IP instead.
|
|
dns:
|
|
- ${DNS_1:-1.1.1.1}
|
|
- ${DNS_2:-8.8.8.8}
|
|
ports:
|
|
- "8080:8080"
|
|
environment:
|
|
# Edit the values here, or leave the ${...} placeholders and set them in a .env file / your stack's env UI.
|
|
SEAFILE_URL: ${SEAFILE_URL:-https://seafile.necloud.us}
|
|
ONLYOFFICE_URL: ${ONLYOFFICE_URL:-https://onlyoffice.necloud.us}
|
|
AUDIOBOOKS_URL: ${AUDIOBOOKS_URL:-https://audiobooks.necloud.us}
|
|
AUDIOBOOKS_LOGIN_LINK: ${AUDIOBOOKS_LOGIN_LINK:-}
|
|
AUDIOBOOKS_SSO_SECRET: ${AUDIOBOOKS_SSO_SECRET:-}
|
|
AUDIOBOOKS_SSO_URL: ${AUDIOBOOKS_SSO_URL:-}
|
|
VERSE_URL: ${VERSE_URL:-https://versebyversewithnate.us/admin}
|
|
WEBMAIL_URL: ${WEBMAIL_URL:-} # optional: a webmail elsewhere; leave empty to use the bundled Roundcube below
|
|
ROUNDCUBE_URL: http://roundcube:80 # the bundled Roundcube; the hub shows it at /webmail/ (it is not exposed to the internet)
|
|
PODCAST_URL: ${PODCAST_URL:-https://podcast.necloud.us/}
|
|
ONLYOFFICE_JWT_SECRET: ${ONLYOFFICE_JWT_SECRET:-} # same value as the OnlyOffice server's JWT secret
|
|
PUBLIC_URL: ${PUBLIC_URL:-} # e.g. https://hub.necloud.us (OnlyOffice posts saved edits here)
|
|
HUB_SETUP_CODE: ${HUB_SETUP_CODE:-} # first passkey; if empty, a code is printed in the log
|
|
SESSION_DAYS: ${SESSION_DAYS:-180} # how long you stay signed in when idle; using the app renews it
|
|
COOKIE_SECRET: ${COOKIE_SECRET:-} # optional; auto-generated and kept in /data if empty
|
|
depends_on:
|
|
- roundcube
|
|
volumes:
|
|
- hub-data:/data # passkeys, calendar links and the session secret live here
|
|
|
|
# Webmail shown inside the Mail tab. Only the hub can reach it (no published port), so it sits behind the passkey sign-in.
|
|
# Sign in to it with your mail address and an app password (Gmail, iCloud and Yahoo are preset in the config below).
|
|
roundcube:
|
|
image: roundcube/roundcubemail:latest-apache
|
|
restart: unless-stopped
|
|
environment:
|
|
ROUNDCUBEMAIL_DB_TYPE: sqlite
|
|
ROUNDCUBEMAIL_REQUEST_PATH: /webmail/
|
|
ROUNDCUBEMAIL_PLUGINS: archive,zipdownload
|
|
ROUNDCUBEMAIL_UPLOAD_MAX_FILESIZE: 30M
|
|
# Microsoft 365 sign-in (optional, see README -> Mail). Leave empty to skip.
|
|
M365_CLIENT_ID: ${M365_CLIENT_ID:-}
|
|
M365_CLIENT_SECRET: ${M365_CLIENT_SECRET:-}
|
|
M365_TENANT: ${M365_TENANT:-}
|
|
PUBLIC_URL: ${PUBLIC_URL:-}
|
|
configs:
|
|
- source: roundcube_hub
|
|
target: /var/roundcube/config/hub.php
|
|
volumes:
|
|
- roundcube-data:/var/roundcube/db # address book, settings and the encryption key
|
|
|
|
configs:
|
|
roundcube_hub:
|
|
content: |
|
|
<?php
|
|
// Settings for the Roundcube that comes with NE Hub.
|
|
$$config['product_name'] = 'Mail';
|
|
$$config['x_frame_options'] = false; // the hub shows this page inside its Mail tab (same address, so only the hub can frame it)
|
|
$$hosts = [
|
|
'ssl://imap.gmail.com:993' => 'Gmail',
|
|
'ssl://imap.mail.me.com:993' => 'iCloud Mail',
|
|
'ssl://imap.mail.yahoo.com:993' => 'Yahoo Mail',
|
|
];
|
|
// Microsoft 365 through OAuth 2.0 (needs an app registration, see README). It goes first because that is where OAuth sign-ins are sent.
|
|
if (getenv('M365_CLIENT_ID')) {
|
|
$$hosts = ['ssl://outlook.office365.com:993' => 'Microsoft 365 (use the Microsoft button)'] + $$hosts;
|
|
$$tenant = getenv('M365_TENANT') ?: 'organizations';
|
|
$$config['oauth_provider'] = 'generic';
|
|
$$config['oauth_provider_name'] = 'Microsoft 365';
|
|
$$config['oauth_client_id'] = getenv('M365_CLIENT_ID');
|
|
$$config['oauth_client_secret'] = getenv('M365_CLIENT_SECRET');
|
|
$$config['oauth_auth_uri'] = "https://login.microsoftonline.com/$${tenant}/oauth2/v2.0/authorize";
|
|
$$config['oauth_token_uri'] = "https://login.microsoftonline.com/$${tenant}/oauth2/v2.0/token";
|
|
$$config['oauth_identity_uri'] = 'https://graph.microsoft.com/oidc/userinfo';
|
|
$$config['oauth_identity_fields'] = ['email', 'preferred_username'];
|
|
$$config['oauth_scope'] = 'email openid profile offline_access https://outlook.office365.com/IMAP.AccessAsUser.All https://outlook.office365.com/SMTP.Send';
|
|
$$config['oauth_login_redirect'] = false;
|
|
if (getenv('PUBLIC_URL')) $$config['oauth_redirect_uri'] = rtrim(getenv('PUBLIC_URL'), '/') . '/webmail/index.php/login/oauth';
|
|
}
|
|
$$config['imap_host'] = $$hosts;
|
|
$$config['smtp_host'] = 'tls://smtp.%z:587'; // smtp.gmail.com, smtp.mail.me.com, smtp.mail.yahoo.com
|
|
$$config['session_lifetime'] = 43200; // minutes (30 days); the hub's own sign-in is what protects access
|
|
// Behind the hub: believe its forwarded address and https.
|
|
if (($$_SERVER['HTTP_X_FORWARDED_PROTO'] ?? '') === 'https') $$_SERVER['HTTPS'] = 'on';
|
|
if (!empty($$_SERVER['HTTP_X_FORWARDED_HOST'])) $$_SERVER['HTTP_HOST'] = $$_SERVER['HTTP_X_FORWARDED_HOST'];
|
|
// A fixed encryption key kept with the data, so saved settings and sessions survive restarts and updates.
|
|
$$kf = '/var/roundcube/db/des_key';
|
|
if (!is_file($$kf)) @file_put_contents($$kf, bin2hex(random_bytes(12)));
|
|
if (is_file($$kf)) $$config['des_key'] = trim(file_get_contents($$kf));
|
|
volumes:
|
|
hub-data:
|
|
name: nehub-data # fixed name so the data survives redeploys and renamed stacks
|
|
roundcube-data:
|
|
name: nehub-roundcube
|