{"result":{"depiction_url":null,"edges":{"subject":{"objects":[{"created":"2026-11-10T10:15:30Z","object_id":{"id":2554,"is_a":["categorization","keyword","keyword_information_type"],"name":"zotonic_topic_how_to_guide","title":"How-to guide","uri":"https:\/\/zotonic.com\/id\/2554"},"seq":1},{"created":"2026-11-10T10:15:30Z","object_id":{"id":2563,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_frontend_developer","title":"Frontend developer","uri":"https:\/\/zotonic.com\/id\/2563"},"seq":2},{"created":"2026-11-10T10:15:30Z","object_id":{"id":2564,"is_a":["categorization","keyword","keyword_audience"],"name":"zotonic_topic_backend_developer","title":"Backend developer","uri":"https:\/\/zotonic.com\/id\/2564"},"seq":3},{"created":"2026-11-10T10:15:30Z","object_id":{"id":2613,"is_a":["categorization","keyword","keyword_domain"],"name":"zotonic_topic_development_and_debugging","title":"Development and debugging","uri":"https:\/\/zotonic.com\/id\/2613"},"seq":4}],"predicate":{"id":308,"is_a":["meta","predicate"],"name":"subject","title":{"_type":"trans","tr":{"en":"Keyword"}},"uri":"http:\/\/purl.org\/dc\/elements\/1.1\/subject"}}},"export_revision":28,"id":3153,"is_a":["text","documentation","developerguide"],"links":[{"rel":"self","target":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3153"},{"rel":"hub","target":"https:\/\/zotonic.com\/.zotonic\/websub"}],"medium":null,"medium_url":null,"name":"doc_guide_docker_windows","page_url":{"en":"https:\/\/zotonic.com\/docs\/3153\/local-development-with-docker-on-windows","x-default":"https:\/\/zotonic.com\/docs\/3153\/local-development-with-docker-on-windows"},"preview_url":null,"resource":{"version":18,"pivot_location_lat":null,"title":"Local development with Docker on Windows","is_authoritative":true,"body":"<h1>Local development with Docker on Windows<\/h1>\n<p>Keep Zotonic in Ubuntu&#39;s Linux filesystem and use Windows launchers for everyday\nwork. This avoids the slow Windows bind mounts and missed file-change events\nthat can affect a checkout under <code>C:\\projects<\/code>. Erlang, PostgreSQL and the media\ntools run in Linux containers; your editor connects to Ubuntu through WSL.<\/p>\n<h2>1. Prepare Ubuntu and Docker Desktop<\/h2>\n<p>Install <a href=\"https:\/\/docs.docker.com\/desktop\/setup\/install\/windows-install\/\">Docker Desktop for Windows<\/a>.\nUse its <strong>WSL 2 backend<\/strong> for this workflow. Docker VMM and Windows containers do\nnot provide the Ubuntu filesystem integration this setup needs.<\/p>\n<p>If Ubuntu is not installed, open <strong>PowerShell as Administrator<\/strong>:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-powershell\">wsl --install -d Ubuntu\n<\/code><\/pre>\n<p>Restart Windows if requested. Open <strong>Ubuntu from the Windows Start menu<\/strong> and\ncreate a normal Linux username and password. Do not use root for development.\nIn that <strong>Ubuntu shell<\/strong>, install Git:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-bash\">sudo apt update\nsudo apt install -y git\n<\/code><\/pre>\n<p>In <strong>PowerShell<\/strong>, check:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-powershell\">wsl --update\nwsl --list --verbose\n<\/code><\/pre>\n<p>Ubuntu must show version <code>2<\/code>. If necessary, use <code>wsl --set-version Ubuntu 2<\/code>,\nsubstituting the exact distribution name shown in the list.<\/p>\n<p>Start Docker Desktop. Under <strong>Settings → Resources → WSL Integration<\/strong>, enable\nthat Ubuntu distribution and apply the settings. Enable <strong>Use WSL 2 based\nengine<\/strong> under General if shown. <strong>Switch to Linux containers<\/strong> is a conditional\nmenu item, not an option every installation shows.<\/p>\n<p>See <a href=\"https:\/\/learn.microsoft.com\/en-us\/windows\/wsl\/install\">Microsoft&#39;s WSL instructions<\/a>\nand <a href=\"https:\/\/docs.docker.com\/desktop\/features\/wsl\/\">Docker&#39;s WSL setup<\/a>.<\/p>\n<h2>2. Run the Windows setup once<\/h2>\n<p>Obtain a current Zotonic checkout or extract the repository archive on Windows.\nThis Windows copy is only used to run setup; it is not mounted into the container.\nWindows Git is not required when using an extracted archive.<\/p>\n<p>In Explorer, double-click <strong>setup-wsl.cmd<\/strong>. No administrator shell is needed.\nIt asks for:<\/p>\n<ul><li>The Ubuntu distribution name, such as <code>Ubuntu<\/code> or <code>Ubuntu-24.04<\/code>.<\/li><li>Your Linux username. Setup rejects root.<\/li><li>The Linux checkout path, defaulting to <code>\/home\/YOUR_USERNAME\/projects\/zotonic<\/code>.\nKeep it inside your Linux home directory, without spaces or special characters.<\/li><\/ul>\n<p>Setup clones Zotonic with Linux Git if that directory does not exist. It can\nreuse an existing Zotonic Git checkout without pulling, resetting, or replacing\nits files. It rejects Windows-mounted paths, even if reached through a symlink.\nThe initial clone uses the Zotonic repository&#39;s default branch.<\/p>\n<p>Setup checks Docker&#39;s Ubuntu integration, starts Docker Desktop if it can find\nit, and offers <strong>Enter to retry<\/strong> or <strong>Q to quit<\/strong> if Docker is unavailable.\nIt installs a launcher folder under <code>%LOCALAPPDATA%\\Zotonic\\WSL<\/code> and creates a\n<strong>Zotonic<\/strong> shortcut to that folder on your Windows desktop.<\/p>\n<p>The folder remembers the distribution, Linux user and checkout path. Rerun\n<strong>Setup Zotonic<\/strong> there to change them. This setup manages one selected checkout\nat a time. Running setup again does not stop a previously selected project;\nstop it before switching profiles. To install newer launcher code, rerun\n<code>setup-wsl.cmd<\/code> from an updated repository copy.<\/p>\n<h2>3. Start Zotonic<\/h2>\n<p>Open the desktop <strong>Zotonic<\/strong> folder and double-click <strong>Start Zotonic<\/strong>.<\/p>\n<p>The launcher starts Docker Desktop when needed, builds the development image,\nstarts PostgreSQL, and starts Zotonic automatically. Compilation on the first\nrun can take several minutes. The sources and <code>_build<\/code> remain inside Ubuntu.<\/p>\n<p>The launcher checks the HTTP endpoint inside the Zotonic container. When it is\nready, it opens <a href=\"http:\/\/localhost:8000\/\">the local status site<\/a> in your Windows\nbrowser. No <code>bin\/zotonic start<\/code> command is needed. The server continues running\nin its container after the launcher window closes.<\/p>\n<p>Use <strong>Logs Zotonic<\/strong> to see compilation and server output. Closing the log\nwindow does not stop Zotonic. Startup errors stay visible. If readiness times\nout, the containers are left available for inspection; use Logs or Stop.<\/p>\n<p>Ports <code>8000<\/code>, <code>8443<\/code>, and the database forwarding port <code>5432<\/code> must be available.\nIf <code>5432<\/code> is occupied, add <code>DB_FORWARD_PORT=5433<\/code> to the Linux checkout&#39;s <code>.env<\/code>\nfile, preserving any existing settings. Zotonic still connects to <code>postgres:5432<\/code>\ninside Docker. Do not change its database host to <code>localhost<\/code>.<\/p>\n<p>If the browser redirects to HTTPS, the development certificate is self-signed.<\/p>\n<h2>4. Create your development site<\/h2>\n<p>Double-click <strong>Shell Zotonic<\/strong>. This opens a shell <strong>inside the running Zotonic\ncontainer<\/strong>, as the Zotonic user, with the correct configuration paths.\nRun:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-bash\">bin\/zotonic addsite -s blog -H mysite.test mysite\n<\/code><\/pre>\n<p>The command creates <code>apps_user\/mysite<\/code>, initializes its database schema and\nstarts the site. Save the generated admin password printed in the terminal.<\/p>\n<p>On Windows, open Notepad as Administrator and edit:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-text\">C:\\Windows\\System32\\drivers\\etc\\hosts\n<\/code><\/pre>\n<p>Select <strong>All files<\/strong> in the file picker to see <code>hosts<\/code>. Add:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-text\">127.0.0.1 mysite.test\n<\/code><\/pre>\n<p>Open <a href=\"http:\/\/mysite.test:8000\/\">your site<\/a> or\n<a href=\"http:\/\/mysite.test:8000\/admin\">its admin<\/a>. Log in as <code>admin<\/code> with the generated\npassword. The status site has separate credentials.<\/p>\n<p>Type <code>exit<\/code> to close the container shell. This leaves the server running.<\/p>\n<h2>5. Edit files<\/h2>\n<p>Install VS Code for Windows with its <strong>WSL extension<\/strong> and the <code>code<\/code> command\non your Windows PATH. Double-click <strong>Edit Zotonic<\/strong> to open the Linux checkout\nthrough VS Code&#39;s WSL connection.<\/p>\n<p>Double-click <strong>Open Zotonic Folder<\/strong> to browse the checkout in Explorer. Its\naddress looks like:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-text\">\\\\wsl.localhost\\Ubuntu\\home\\YOUR_USERNAME\\projects\\zotonic\n<\/code><\/pre>\n<p>Keep the working files there rather than copying them back to a Windows drive.\nSite templates are under <code>apps_user\/mysite\/priv\/templates<\/code>. Zotonic receives\nLinux file-change notifications for the checkout. To explicitly rebuild, open\n<strong>Shell Zotonic<\/strong> and run <code>make<\/code>.<\/p>\n<h2>6. Stop and return later<\/h2>\n<p>Double-click <strong>Stop Zotonic<\/strong>. It stops and removes the managed project&#39;s\ncontainers and network, allowing up to 60 seconds for shutdown. The PostgreSQL\nvolume, source files, uploaded files and configuration remain saved. Docker\nDesktop stays running; it can be quit separately from its system-tray menu.<\/p>\n<p>Next time, double-click <strong>Start Zotonic<\/strong>. Your site and database remain.<\/p>\n<p>The repository&#39;s Windows <code>start-docker.cmd<\/code> and <code>stop-docker.cmd<\/code> also use this\nsaved WSL setup. They no longer mount the Windows checkout. The standalone\n<code>.\/start-docker.sh<\/code> and <code>.\/stop-docker.sh<\/code> are for the separate manual container\nworkflow; use the Windows launchers together for this managed setup.<\/p>\n<p>Avoid <code>docker compose down -v<\/code>: <code>-v<\/code> removes database volumes.<\/p>\n<h2>Moving from the old Windows checkout<\/h2>\n<p>First stop the old containers. If using the previous interactive setup, run\n<code>bin\/zotonic stop<\/code> and <code>exit<\/code> in its container, then run <code>docker compose down<\/code>\nfrom PowerShell in the old Windows checkout. Do not add <code>-v<\/code>.<\/p>\n<p>Keep the old checkout and database volume until migration is complete. Setup\ncreates a separate Compose project whose name starts with <code>zotonic-wsl-<\/code> and is\nbased on the distribution and Linux checkout path. Existing Windows project\ndatabases are <strong>not automatically migrated<\/strong>. Copy your site source files and\ntransfer the database with PostgreSQL backup\/restore; preserve uploaded files\nand any needed configuration under <code>docker-data<\/code> as well. Do not copy <code>_build<\/code>\nfrom the old checkout.<\/p>\n<p>Setup does not reset local edits or delete the old project. Moving or renaming\nthe Linux checkout changes its managed Compose project identity, so keep its\npath stable once it contains data.<\/p>\n<h2>Troubleshooting<\/h2>\n<h3>Docker is unavailable<\/h3>\n<p>The retry prompt waits for you to resolve Docker Desktop startup or integration\nerrors. Press Enter to check again, or Q to leave. In PowerShell, open the exact\nUbuntu distribution and user selected during setup:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-powershell\">wsl -d Ubuntu -u YOUR_USERNAME\n<\/code><\/pre>\n<p>Then, in Ubuntu:<\/p>\n<pre class=\"notranslate\"><code class=\"notranslate language-bash\">docker version\ndocker compose version\ndocker info --format &#39;{{.OSType}}&#39;\n<\/code><\/pre>\n<p>The engine type must be <code>linux<\/code>. A missing <code>docker<\/code> command usually means Ubuntu\nWSL integration is disabled. Do not install a second Docker Engine with <code>apt<\/code>.<\/p>\n<h3>User or group ID is zero<\/h3>\n<p>Rerun setup and choose the normal Linux user created during Ubuntu installation.\nThe managed launchers use that user&#39;s IDs and ignore stale UID\/GID overrides.<\/p>\n<h3>The credential helper fails<\/h3>\n<p>For <code>docker-credential-desktop.exe: Invalid argument<\/code>, save your WSL work, quit\nDocker Desktop, and run <code>wsl --shutdown<\/code> in PowerShell. This stops all WSL\ndistributions. Start Docker Desktop and retry Start Zotonic. If it still fails,\ncheck <code>cmd.exe \/c ver<\/code> and <code>command -v docker-credential-desktop.exe<\/code> in Ubuntu;\nkeep the diagnostic output rather than deleting Docker credential settings.<\/p>\n<h3>A script reports <code>bash\\r<\/code> or <code>sh\\r<\/code><\/h3>\n<p>A script has Windows CRLF endings. Fresh clones made by setup use Linux Git\nwith <code>core.autocrlf=false<\/code>. If you copied scripts from the old Windows checkout,\nchange their line endings to LF in VS Code and retry. Git attributes do not\nrewrite existing files automatically.<\/p>\n<h3>Validation status<\/h3>\n<p>The launcher shell logic and Compose configuration can be tested without\nWindows. Full Windows Desktop\/WSL integration still needs verification on a\nWindows machine.<\/p>","slug":"local-development-with-docker-on-windows","is_protected":false,"visible_for":0,"tz":"UTC","language":["en"],"doc_source_hash":"69b15b51a5cd2bad5d3dc9f6d2350e45f438cf1b5097f06dfcfe66ab33da340b","is_featured":false,"content_group_id":{"id":2551,"is_a":["meta","content_group"],"name":"content_group_imported_docs","title":"Imported documentation","uri":"https:\/\/zotonic.com\/id\/content_group_imported_docs"},"category_id":{"id":317,"is_a":["meta","category"],"name":"developerguide","title":"Developer guide","uri":"https:\/\/zotonic.com\/id\/developerguide"},"doc_source_path":"doc\/guides\/docker-windows.md","publication_start":"2026-11-10T10:15:30Z","github_url":"https:\/\/github.com\/zotonic\/zotonic\/blob\/master\/doc\/guides\/docker-windows.md","pivot_location_lng":null,"doc_source_kind":"guide","name":"doc_guide_docker_windows","is_unfindable":false,"is_published":true,"pivot_geocode":null,"created":"2026-11-10T10:15:30Z","uri":null,"doc_status":"current","is_dependent":false,"publication_end":"9999-06-01T00:00:00Z","modifier_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"privacy":0,"doc_source_commit":"8e6aad17c4d86dee983db46a656ed6f6a930bcbb\n","creator_id":{"id":1,"is_a":["person"],"name":"administrator","title":"Site Administrator","uri":"https:\/\/zotonic.com\/id\/1"},"modified":"2026-11-11T14:07:34Z","title_slug":"local-development-with-docker-on-windows"},"uri":"https:\/\/zotonic.com\/id\/3153","uri_template":"https:\/\/zotonic.com\/id\/:id","version":28,"websub":{"hub":"https:\/\/zotonic.com\/.zotonic\/websub","topic":"https:\/\/zotonic.com\/.zotonic\/websub\/topic\/3153"}},"status":"ok"}