plausible

Stars and mentions

Last 30 days, Oct 5 – Nov 3

GitHub stars291
mentions14
05101520Oct 5Oct 19Nov 3
UTC days · repositories plausible owns1 repositories

Package downloads

Cumulative recorded downloads · since 2025-10-19

npm3.7M
0936.8K1.9M2.8M3.7MOct 5Oct 19Nov 3
Oct 19npm: 2/3 packages observed

Across 3 known packages in repositories plausible owns. Cumulative totals include recorded downloads before the selected range. Missing observations leave gaps; totals may be incomplete.

Top repositories

plausible’s repositories ranked by new forks, as on trending.

Loading

Contributes to

Repositories outside plausible’s account where plausible opened or reviewed pull requests in the past 365 days.

Who noticed plausible

Everyone who starred or forked plausible’s repositories since the archive began in 2011.

Notable accounts

Ordered by the stars their own repositories have received.

Biggest fans

Accounts that starred the most of these repositories.

Breakout weeks

Each repository’s best week of new stars, with the release published around it.

Mentions

14posts
Nov 40 posts
  1. Bringing Tuist to Elixir --- title: "Bringing Tuist to Elixir" published: true description: "We use Elixir every day to build Tuist. Now we're bringing build and test insights, sharding, and dependency caching to the ecosystem we love." tags: elixir, tuist, devops, testing canonical_url: tuist.dev cover_image: tuist.dev --- We are very fond of Elixir. An idea in Joe Armstrong's thesis helped convince us to build Tuist's server with it: model software after the real world, as concurrent processes that communicate with each other. To us, software becomes easier to understand and maintain when its structure follows the world it's modelling. Since then, we've built much of Tuist in Elixir. Phoenix lets us build dynamic experiences and test the UI in the same language, without maintaining a separate single-page application. Hot code reloading makes it easy to iterate. We're a small team, and being able to do all of that in Elixir has mattered a lot. José Valim has also been very supportive along the way. It's funny that, with agents, we're starting to appreciate many of Erlang's primitives again. An agent might need to keep working for hours, communicate with other agents, and recover from failures. Processes, message passing, and supervision give us a lot to work with. We still need to persist state if we want to recover it after a restart; a supervisor doesn't do that for us. But we don't have to build the whole model ourselves. And we can look into the runtime while it's running. Which processes are consuming memory? Where is the CPU time going? Those questions become important when something works for much longer than a web request, and agents can use the same interfaces to investigate. The more we use Elixir, the more convinced we are that we chose well. Bringing Tuist to more build systems That appreciation for Elixir is part of why we're announcing support for it today. The other part has to do with what we're building at Tuist. We started with builds and tests: understanding where the time goes, avoiding repeated compilation, and getting test results sooner. We already do that for Xcode, Gradle, and Bazel. Our principle is to bring that work to more toolchains, so teams can benefit from it where they already are. Of course, the toolchains don't all have the same capabilities. Mix doesn't come with shared compilation caching or remote execution out of the box. Language design decisions also affect what we can offer. But what if we work with those ecosystems to help make more of it possible, including contributing to the toolchains themselves? We see ideas moving between build systems already. Working across them lets us participate in that: learn how one solves a problem, then explore whether the same idea makes sense elsewhere. It won't always, and we need to be honest about the limitations. But with agents producing more code to compile and test, we think there's a growing incentive to do that work. We're also betting that models will keep getting better at working with each toolchain. They still need infrastructure to query build and test data, reuse compiled work, and distribute execution. That's the part we're building. So when we asked ourselves which ecosystem to support next, Elixir felt obvious. We understand it, we use it every day, and we can dogfood the integration on Tuist itself. We also think it deserves more attention when it comes to build and test infrastructure. We'd like to help give it that attention. When we see teams like Remote, Discord, Supabase's Realtime team, or Apple's Environmental Systems team betting on Elixir, we want them to have build and test tooling that grows with their projects. And there's WhatsApp, which built its messaging backend with Erlang, sharing the same runtime as Elixir. We get so much from this ecosystem. Helping organizations move faster with it feels like a good way to contribute. Here's what we've built so far. If you'd rather watch, we've recorded a walkthrough on YouTube. {% embed youtube.com %} Getting started with Tuist and Mix Before going into the features, sign in or create an account, then create a project in the dashboard and choose Mix (Elixir) as its build system. Its handle, account/project, connects your local Mix project to the one on Tuist. Add our Hex package to your existing dependencies in mix.exs. You'll need Elixir 1.18 or later, but you don't need the Tuist CLI: defp deps do [ {:tuist_ex, "~> 0.10.0", runtime: false} ] end Then fetch it, configure it with your project handle, and log in: mix deps.get mix tuist.setup --project account/project mix tuist.login Setup updates mix.exs with the project configuration, enables dependency caching, and installs the compile and test aliases. Login opens your browser to authenticate. Commit the configuration, and keep using mix compile and mix test as usual. The Elixir guide covers the details. In CI, use a token or authenticate through OpenID Connect (OIDC) with a supported provider; the authentication guide walks you through both options. Build insights for Elixir It's easy to look at a slow build and think we need a bigger machine. But if most files are waiting for a handful of modules to compile, more cores won't help much. We need to understand why those dependencies exist. Gettext is a good example. Before version 0.26, importing an application's Gettext backend to use its macros created a compile-time dependency on that backend. Many views and controllers could end up waiting for the same module, and changing a translation could trigger recompilation across much of the application. Separating the macros from the generated backend removed those dependencies. That improvement didn't require a bigger machine. But to find a problem like that in your own project, you need to see more than the build's total duration. Tuist records which files compiled, the modules they define and depend on, and how much time they spent compiling or waiting. You can sort files by compilation time or by how many other files depend on them. A slow file that the rest of the application waits for is worth investigating before one that compiles independently. !Build trends and Elixir-version configuration insights for a Phoenix project The real Builds dashboard, populated with synthetic data for a Phoenix demo project. The timeline lets you follow that work alongside type checking, writing modules to disk, and the machine's CPU, memory, network, and disk usage. If the CPU is mostly idle during a long wait, you can look at what the compiler was waiting for. Warnings, errors, and the build's outcome are recorded with it. !A Mix compilation timeline alongside CPU, memory, network, and disk measurements A clean compilation in the same synthetic demo, with file compilation, type checking, and machine metrics on one timeline. We want agents to be able to investigate this too. Build summaries, including durations, warning and error counts, and cache activity, are already available through the API and our MCP tools. The per-file graph and detailed timeline are currently in the dashboard; we still need to expose those for agents to do the same investigation. From there, we can connect a file's compilation history with its position in the graph and how often it changes. A frequently edited module that forces half the application to recompile is a different problem from an expensive module that rarely changes. We'd like an agent to identify those cases, suggest a change, and use subsequent builds to check whether it helped. For now, the Elixir build insights guide covers how to collect the data and explore it yourself. We think it's worth doing before build times become a problem for the team. Test insights for ExUnit Tests have a similar problem: the output of one run tells you what happened, but not much about how the suite is changing. Is that test getting slower? Has it failed before with the same code? We collect individual results and durations, including doctests, organized by module and describe block. Failures keep their message and location, so you and your agents can follow them across runs through the dashboard, API, or MCP. Elixir gives us a good starting point for improving the suite, too. Each ExUnit test runs in its own process. If we avoid shared state, asynchronous test modules can run concurrently, using more of the available cores for CPU-bound work. Databases and external services aren't isolated just because the tests have separate processes, so there's still work to do in how we design them. The test insights guide covers what we collect to help with that work. Test sharding Once we know how long the tests take, we can use that information to distribute them across CI runners. ExUnit handles concurrency within one machine; sharding lets us spread the suite across several. There are already good ways to split a suite. Plausible's CI, for example, uses Mix's built-in partitioning across six runners. Mix sorts the test files and distributes them round-robin, so there's no manual file list to maintain. But an equal number of files doesn't mean an equal amount of work. One runner can still be busy long after the others finish. Tuist uses historical timings to assign the files instead. You choose how many shards you want, for example with --shard-total 4, or set a target maximum duration per shard and a limit on the shard count. As the suite changes, the plan changes with it. New files get estimates until we have measurements. You shouldn't need to keep moving files around to stop one runner holding up the rest. We also don't want each runner to compile the same project. Tuist compiles it once, uploads the build, and lets the runners download it and execute their assigned files. Their results appear as a single test run, with each shard's duration available in the dashboard. The sharding guide covers the CI setup, including any database preparation your project needs. We measured this locally on our own server: successful full-suite runs took 44.4% less wall-clock time with four shards, running the same tests with the same total CPU budget. !An Elixir test run combining results from four shards, with their individual durations Four shards reported as one test run in the real dashboard, using synthetic data for the Phoenix demo project. Flaky tests A faster suite isn't much help if you learn to ignore its failures. When the same test keeps passing on a retry, it's tempting to assume the next red build is just that test again. We want to keep the evidence of that flakiness, even when the retry turns CI green. Tuist compares passes and failures on the same commit across CI runs. You can also opt in to retries, which report a test that fails and then passes as flaky: mix test --retries 2 Those attempts stay in the test's history. By default, an automation marks the test itself as flaky after three flaky runs in 30 days. You can change the threshold and recovery window in the project's automation settings, or mark a test manually. While a fix is in progress, you can quarantine the test from the dashboard. Muting keeps it running and reporting failures, but those failures don't block an otherwise successful, complete run. Skipping leaves it out of the run. You can set either state manually or have an automation do it when a test becomes flaky, then return it to Enabled once you've fixed it. Quarantine requires authentication, even for public projects. For now, muting doesn't apply with --warnings-as-errors or from an umbrella project's root. Skipping uses a name filter, so it can also exclude a same-named test in another module, and explicit include filters can bring a skipped test back. Those limits matter when deciding how to use it in CI. Once a test is flagged, you can notify the team through Slack. Or, with an event-capable client and a webhook, use the test_case.marked_flaky event from our MCP Events interface to have an agent investigate its history and failures. We'd like to get to a point where those investigations start without someone having to notice the problem in CI first. The flaky tests guide covers detection, retries, quarantine, and notifications. Code coverage Sharding also changes how we need to collect coverage. Four runners each see only part of the suite. We need to bring those measurements together before saying how much of the code the tests exercised, and make sure restoring compiled code from a cache doesn't leave it out. Coverage is in early access and needs to be enabled for your account. Once enabled, the package reports it alongside the test results when you run: mix test --cover You can inspect the results by file, function, and OTP application. With sharding, enable --cover both when building the shards and when running them. After every job measuring coverage for a commit has finished, a final CI job marks it complete: mix tuist.coverage.complete That tells us when to reconcile the reports for the branch's coverage trend. If you deliberately run only part of the suite, we report the coverage as partial. The package's coverage reference covers the setup. !Elixir code coverage trends, covered and executable lines, and changes by source file and OTP application The real Code Coverage dashboard with synthetic data for the Phoenix demo project: coverage over time, and changes across Elixir files and OTP applications. We're working on selective testing next, using coverage data to understand which tests exercise the code that changed. That would let us run the affected tests instead of the whole suite for every change. It isn't available for Elixir yet, but we hope to let teams try it soon. Elixir dependency caching We use a lot of dependencies, and CI keeps compiling the same versions. It feels wasteful, especially when another build has just done that work. But before we reuse a result, we need to know what went into it and what we'd skip by not compiling again. The same inputs must produce the same outputs, without side effects that the next build still needs. That's what we mean by hermetic compilation. A macro can read an environment variable, a file outside the dependency, the clock, or a network response while compiling. We can't automatically discover all of those reads. If an input changes without us knowing, we might reuse stale code. We started with dependencies because their resolved versions and sources give us a useful starting point. The cache key also includes upstream compiled dependencies and resources, the toolchain, compiler options, effective application configuration, Mix environment and target, and any additional inputs you declare. The setup above enables caching for supported Hex and Git dependencies using the standard Mix pipeline with Elixir or Erlang sources, and ordinary rebar3 compilation. It doesn't cache your application's own source files. You'll need to declare additional file and environment inputs where compilation uses them. Dependencies that rely on time, network responses, or side effects that must happen on every build should be excluded. Native and custom builders need an explicit audit and configuration of their build environment, required outputs, and additional inputs. Otherwise they compile normally, as do local dependencies and unsupported dependency chains. Using the standard compiler doesn't, on its own, prove that a dependency is hermetic. The advanced cache guide goes into that in more detail. When we can reuse a result, Tuist looks locally first, then in the shared remote cache. A miss compiles normally and stores the result for later builds. If the cache or authentication is unavailable, compilation falls back to Mix. You can see the hits, transfers, and recent builds in the Mix Cache dashboard. !The Mix Cache dashboard showing hit-rate trends, cache transfers, latency, throughput, and recent builds The real Mix Cache dashboard with synthetic client cache observations. These numbers illustrate the interface, not measured performance or savings. We tried it on our own server: compilation took 33.6% less time with a warm local dependency cache, while still compiling all of our application's own code. Of course, looking up and downloading compiled code takes time too. That's why we've invested in Kura, our distributed cache infrastructure. It replicates artifacts between cache nodes so builds can fetch them nearby. With our runners, we can place the cache close to the compute and reuse artifacts across jobs. We don't want to save time compiling only to spend it transferring the result. The Elixir cache guide covers getting started. Giving something back to Elixir Elixir has given our small team a lot. We get to build and operate software that would be harder for us to manage otherwise. We're thankful for that, and we'd like this work to be useful to the people building alongside us in the ecosystem. We've been using this integration on our own server for weeks. The Tuist server project is public, so you can look at real build and test data, beyond the synthetic examples in this post. There's also a public project for Livebook you can explore. If you maintain an open-source Elixir project, our open-source program gives you free access to these build and test features. [Send us your repository and Tuist account handle](mailto:contact@tuist.dev), and we'll help you get set up. And if you're using Elixir at work, we'd like to hear how your builds and tests are going. Where do you spend time waiting? What have you had to build yourselves? You can book a call with us to talk about it. We have our own experience running Tuist, but there's a lot more for us to learn from yours.

  2. 5. Plausible 数据分析无需谷歌,完全隐私保护。 自建服务器部署,成本直接降到零。 plausible/analytics

    61 views
  3. Convertr Supply Chain Attack: Magecart Skimmer Injected into Plausible Tracker to Steal Payment Data 1. Overview - Article Name: Notorious Brazilian Magecart group hijacks Convertr checkouts via outdated Plausible install - Source: Sansec - Publication Date: 2026-10-26 - Updated Date: 2026-10-27 - Original: Sansec - Related Sources: BleepingComputer: Convertr supply-chain attack, Plausible CVE-2026-8467 advisory - Related Malware, Threat Groups, CVEs, Products: Web skimmer, Brazilian Magecart group, CVE-2026-8467, Convertr, Plausible Community Edition - Severity: Critical 2. Executive Summary A notorious Brazilian Magecart group injected a web skimmer into the Plausible Analytics script distributed by the Brazilian e-commerce platform Convertr, causing modified trackers to load across merchant checkout pages. The skimmer was designed to steal credit card numbers, expiration dates, security codes (CVV), cardholder names, and CPFs (Brazilian taxpayer IDs) from targeted checkout pages, transmitting the data to the exfiltration endpoint 1x0.is/ws. Note that this does not mean data theft was successfully confirmed for every single buyer. Although the compromised script was removed on October 27, 2026, Sansec has not confirmed that CVE-2026-8467 was the entry point. Sansec had not reviewed Convertr's server logs, so this remains a suspected entry point rather than a confirmed finding. Sansec reported payment data theft through a shared tracker, illustrating how tampering with one server can affect multiple e-commerce merchants. Because the exploitation of the initial vulnerability remains unconfirmed, verified facts and inferences are clearly distinguished and organized. 3. Attack Flow Payment Data Theft via Shared Analytics Script 1. An attacker modifies the Convertr Plausible tracker file (identified by Sansec as /js/script.pageview-props.tagged-events.js) and embeds obfuscated web skimmer code. 2. The web browsers of visitors to merchant checkout pages load the modified shared tracker, and the skimmer dynamically extracts card numbers and CPF information from payment input forms and API requests. 3. Base64-encoded payment data records are transmitted directly from the user's browser to the external server 1x0.is/ws. The following table outlines the attack flow and investigation considerations based on Sansec's analysis and public disclosures. It does not confirm that payment data was stolen from every merchant or all buyers. Inference: The defender indicators in the table are investigation candidates. Logs, browser telemetry, and Content Security Policy (CSP) violation reports depend on deployment settings and retention scopes. | Attack Stage | Attacker Action / Technique | Tools / Communications | Defender Indicators (Prerequisites / Artifacts) | | --- | --- | --- | --- | | Tracker Tampering | Injects obfuscated Magecart skimmer code into the tracker file on the Convertr Plausible server. | Server intrusion method unconfirmed (CVE-2026-8467 is Sansec's suspected entry point), obfuscated JS code | Changes in tracker file hash, added obfuscated strings or eval in the file, file modification time discrepancies | | Script Delivery and Execution | Merchant checkout pages load the modified tracker, initializing the skimmer in the browser. | Shared tracker loading, browser cache (CDN usage unconfirmed) | Script retrieval from analytics.convertr.app.br, compromised script saved in browser cache (up to 24 hours) | | Payment Form Monitoring and Theft | Executes when the URL matches checkout.convertr, extracting card data and CPF from form inputs and Payment API requests. | DOM event listeners, API hooks | Suspicious JS behavior during form input on checkout screens, interception artifacts in Payment API calls | | External Data Exfiltration | Base64-encodes collected card numbers, expiration dates, CVV, names, and CPF, and sends them via HTTP POST to an attacker-controlled exfiltration destination. | HTTP POST traffic, 1x0.is/ws | POST requests from the browser to an unknown domain 1x0.is (port 443). CSP violation reports are additional investigation candidates subject to destination constraints and reporting configurations, and do not constitute proof of successful exfiltration | 4. Attacker Positioning and Execution Location - Positioned to modify tracker files on the Convertr analytics server. CVE exploitation is unconfirmed. 5. Victim and Administrator Perspective - Victims: Checkout may appear to work normally, making the theft difficult to detect from the page alone. - Administrators: Investigation leads include changes to third-party script hashes, added obfuscated code or eval, and browser traffic to unexpected .is domains, where the relevant telemetry is available. 6. Success and Failure Conditions Success Conditions - The modified tracker is loaded from the browser cache or server. - The URL matches checkout.convertr, and the user enters payment details and places an order. Failure Conditions and Mitigations - Revert the tracker to a clean version and force an update or invalidation of the browser cache. According to Sansec, compromised scripts remain in the cache for up to 24 hours, so server-side removal alone does not immediately eliminate risk for all users. - Update to Plausible CE 3.2.1 or later and investigate access to /storybook. If such access is found, follow Sansec's procedures to rebuild the server, rotate secrets, and compare tracker files with the official version. - Inference: Consider implementing Content Security Policy or script integrity verification for checkouts. Domain allowlists alone may not protect against the tampering of already-permitted scripts. 7. What Happens Upon Success - Theft of card numbers, expiration dates, CVV, names, and CPF. - Browser-side supply chain compromise simultaneously affecting multiple merchants. 8. Observable Logs Inference: The following are investigation candidates based on public disclosures and identifiers. The reviewer has not verified on deployed systems which events are logged or which fields are available. Results depend on configuration and log retention, and a single match does not confirm successful compromise. - Email: No specific email-related indicators identified. - Proxy / SWG / DNS: Verify POST requests to 1x0.is/ws and script retrieval from analytics.convertr.app.br. - Endpoint / EDR: Preserve compromised scripts remaining in the browser cache of checkout terminals. - Identity / IdP: No specific information. - SaaS / Cloud: Check analytics server /storybook requests, file modifications, and administrative operations. - Network: Verify the SHA-256 hash ee4618d24737eff785e5a267b55903d5ef6ff7ecbeb099347a67fee77734d7f7 of the retrieved script (2026-10-26 sample). 9. Attack Success Determination - Payment Data Exfiltration — Assessment Criterion: Confirm that a payload containing payment data was sent from a user's browser to 1x0.is/ws. Sansec analyzed the malicious script and its transmission code; this does not establish the number of individual victims. 10. Investigation Playbook 1. Trigger: 1x0.is/ws traffic or tracker hash match 2. Initial Review: Check merchants, timeframes, browser caches, and server logs 3. Endpoint Investigation: Preserve cache and network evidence from victim terminals 4. Identity & Cloud: Check Plausible host access, file modifications, and secret usage 5. Follow-up Operations: Investigate card fraud and whether other merchants received the same compromised tracker 6. Containment: Remove scripts, invalidate caches, patch systems, rotate secrets, and notify stakeholders 7. Distinction of Phases: Distinguish between script delivery, data entry, exfiltration, and financial loss 11. Defense and Detection Ideas - Single Event: POST requests from checkout pages to unknown .is domains - Timeline Correlation: Tracker update → Checkout load → Card entry → Exfiltration - Hunting: Monitor hash discrepancies in shared analytics assets - Log Gaps: Without browser telemetry, individual exfiltration events are difficult to identify - Priority Actions: Prioritize Plausible updates and script integrity monitoring 12. Facts, Inference, and Hypothesis Facts - From October 24, 2026, Convertr checkouts transmitted card data and CPFs to 1x0.is/ws. - The skimmer operated only on checkout.convertr, base64-encoding and transmitting card numbers, expiration dates, CVV, names, and CPFs. - Attackers updated the skimmer on October 26 to match exact Convertr payment API field names. - Convertr removed the skimmer on October 27, updated Plausible to a patched version, and Sansec confirmed the tracker was clean. - Sansec was unable to review server logs and has not confirmed whether CVE-2026-8467 was the actual initial access vector. Inference - Integrity monitoring for shared analytics scripts must be handled with the same rigor as monitoring the checkout application itself. Hypothesis No additional hypotheses. Unverified items are listed under Unknowns and Further Investigation. 13. MITRE ATT&CK Mapping There are no actionable mappings with confirmed evidence. 14. Unknowns and Further Investigation - The number of affected purchases and the scope of impacted merchants. - Whether CVE-2026-8467 was the actual initial access vector. 15. Impact on SOCs and Organizations Organizations using cross-border e-commerce or payment services for Brazil should monitor for browser-side supply chain compromises involving third-party tracker tampering and prepare for potential card data and personally identifiable information leaks. 16. Summary by Role - For SOCs: Investigate scripts originating from analytics.convertr.app.br and browser communications to 1x0.is/ws. - For Administrators: Update Plausible CE to version 3.2.1 or later, verify tracker file hashes, and check for access to /storybook. - For Users: If you entered card details on an affected checkout page, contact your financial institution to request a card replacement and monitor for unauthorized activity.

    1 reaction
  4. @ferron_web Thanks for flagging this! There’s a known bug in how the hourly chart handles the repeated hour when clocks go back. It affects the chart, while tracking and stored data are unaffected. A fix is in progress, see: analytics#6626

    2 likes · 9 views
  5. @mehdi_khoudali Open source. Free when self-hosted. With a proven track record. plausible/analytics

    1 like · 63 views
  6. 6、open source:买软件前先搜开源 看到一个软件收费很贵? 先试试在工具类型后面加上 open source。 你可能会找到可以自行部署、修改的开源替代品。 搜索: web analytics open source Notion open source alternative 延伸阅读:Plausible 开源网站分析项目 plausible/analytics

    1 like · 24 views
  7. Plausible Analytics: Open source, privacy-first web analytics. Lightweight, cookie-free Google Analytics alternative. Self-hosted or cloud (30k stars) What it does All text below is quoted directly from the project README. >Plausible Analytics is an open source, privacy-first web analytics tool. Lightweight, cookie-free alternative to Google Analytics. Why Plausible? Here's what makes Plausible a great Google Analytics alternative and why we're trusted by thousands of paying subscribers to deliver their website and business insights: - Clutter-free Plausible provides simple web analytics that cut through the noise. No layers of menus or need to create custom reports. All key insights are on a single page, with no training required. - Privacy-first and compliant Measure traffic, not individuals. No personal data or IP addresses are stored, and no cookies or persistent identifiers are used. Fully compliant with GDPR, CCPA and PECR. - Lightweight Our script is tiny, helping your website load faster. You can also send events directly to our events API. - Built for modern workflows Works with modern frameworks and supports SPAs out of the box, including pushState and hash-based routing. - Define key goals and track conversions Track goals, conversions, revenue attribution and funnels using custom events and dimensions. Turn on codeless tracking for outbound link clicks, form completions, file downloads and 404 error pages. - Easy reporting and sharing Get weekly or monthly reports via email or Slack, including traffic spike/drop notifications. Invite team members with role-based access, share dashboards publicly or with anyone using a simple link. Make your analytics transparent by default. - Search insights included Integrate with Google Search Console to get accurate keyword data directly in your dashboard. - API and integrations Send events directly via our API and export your stats using the stats API or CSV. Build custom workflows and integrations on top of your data. - Real-time insights Monitor live traffic and understand what's happening on your site as it happens. Repository plausible/analytics

    1 point
  8. GitLab CE vs Forgejo: Self-Hosted Git on Docker, Measured GitLab CE and Forgejo both give you a private Git server with issues, code review, CI and a container registry. They sit at opposite ends of the weight scale. This comparison ran both under Docker Compose on the same box, pushed a real pipeline through each runner, pushed an image to each registry, migrated the same GitHub repository into both and ran each backup command. The numbers below come from that run on October 19, 2026. TL;DR: - On an 8 vCPU host, Forgejo 15.0.10 with Postgres and a runner idled at 285.7 MiB of RAM and under 1% of one CPU core. GitLab CE 19.5.0 with its runner idled at 8,722.6 MiB with default settings. The GitLab container alone dropped to 2,466.5 MiB with the memory-constrained settings from the GitLab docs. - Forgejo answered its health check 5.4 seconds after docker compose up -d. GitLab served its sign-in page after 145 seconds. - Both ran a trivial CI job, accepted a docker push to the built-in registry, migrated a GitHub repo and wrote a backup archive of 15.6 MB (Forgejo) or 16.2 MB (GitLab). - GitLab CE is MIT licensed, with paid features under a separate EE license. Forgejo is GPL v3 or later. Forgejo federation is experimental and off by default. - Pick Forgejo for a small team or a homelab VPS. Pick GitLab CE when you want its integrated CI/CD and project management and can give it 8 GB or more of RAM. Table of contents The measured numbers Idle RAM and CPU Each stack ran alone on the same 8 vCPU host. The numbers are idle averages from docker stats, taken after each stack had run a pipeline, a registry push, a migration and a backup. 100% CPU means one full core. !Bar chart of idle memory on the same 8 vCPU host. Forgejo 15.0.10 stack with server, Postgres and runner: 285.7 MiB. GitLab CE 19.5.0 with memory-constrained settings, GitLab container only: 2,466.5 MiB. GitLab CE 19.5.0 with default settings plus runner: 8,722.6 MiB. | Stack | Avg RAM | Peak RAM | Avg CPU | Peak CPU | | --- | --- | --- | --- | --- | | Forgejo 15.0.10 + Postgres 17.11 + runner 13.2.0 | 285.7 MiB | 300.1 MiB | 0.57% | 0.89% | | GitLab CE 19.5.0 default + runner 19.5.0 | 8,722.6 MiB | 8,797.6 MiB | 16.50% | 87.05% | | GitLab CE 19.5.0 memory-constrained (container only) | 2,466.5 MiB | 2,537.5 MiB | 9.29% | 74.12% | The constrained row leaves out the runner, so add about 65 MiB to compare it with the others. GitLab's default memory also depends on the server. Per the GitLab Puma docs, it starts one Puma worker per CPU, limited by RAM at about 1 GB each, so a 2 vCPU server starts fewer workers than this 8 vCPU host did. Inside Forgejo, the server process took about 204 MiB, Postgres about 73 MiB and the idle runner about 8 MiB. GitLab is one container with many services. gitlab-ctl status listed 16 of them, including Puma, Sidekiq, Gitaly, PostgreSQL, Redis, Prometheus, Alertmanager, the registry and several exporters. With default settings, ps inside the container showed ten Ruby processes at roughly 1 GB of resident memory each, and the cgroup reported 8,022 MiB of anonymous memory. The GitLab runner added about 65 MiB. The default GitLab number is in line with what people report on the GitLab forum. In a 2018 thread, one user who had just installed the gitlab-ce container with a single account and no code saw 8.452 GB in docker stats. The installation requirements set 16 GB and 8 vCPU as the single-node baseline, and at least 8 GB for memory-constrained setups. The memory-constrained profile comes from the GitLab docs page for small environments, which states that "With some adjustments, GitLab can run comfortably on much lower specifications than described in minimum requirements or the reference architectures." The lab applied the page's Puma, Sidekiq, Prometheus and jemalloc settings, plus the Gitaly spawn limit, but not the Gitaly per-repo concurrency block. On this host that cut the GitLab container's idle RAM by about 72%, and a pipeline still ran green. The same page asks for at least 2 GB of RAM plus 1 GB of swap and warns that functionality and performance can degrade. Forgejo 17.0.0, released October 15, 2026, idled at 315.3 MiB on the same host. As of October 19, 2026, the 17.0.0 release page advises against upgrading because of an issue that "prevents pushing, merging, or other code operations in some cases," so the rest of this guide uses the 15.0 LTS line. Install time and steps | | Forgejo 15.0.10 | GitLab CE 19.5.0 | | --- | --- | --- | | Images | forgejo 188 MB, postgres 297 MB, runner 46 MB | gitlab-ce 4.07 GB, gitlab-runner 245 MB | | Pull time on this host | 3 to 7 s per image | 53 s for gitlab-ce | | up -d to ready | 5.4 s (/api/healthz passes) | 145 s (/users/sign_in returns 200) | | Admin account | forgejo admin user create | GITLAB_ROOT_PASSWORD on first boot | | Runner setup | generate token, register, restart runner | create runner in UI or API, register | Image sizes are the local uncompressed sizes from docker images. GitLab also pulled its helper image, gitlab-runner-helper:x86_64-v19.5.0 (112 MB), on the first job. Switching GitLab to the constrained settings and recreating the container took another 98 seconds before the sign-in page came back. Install both with Docker Compose Both stacks below publish ports on 127.0.0.1 only. Put a TLS proxy such as Nginx Proxy Manager in front before anyone else uses them, the same pattern as the Plausible CE guide. Forgejo with Postgres and a runner The Forgejo Docker docs start from a single server service and add Postgres as an option. The file below adds Postgres, skips the web installer with INSTALL_LOCK, and adds a runner that waits until it has been registered: name: fj services: server: image: codeberg.org/forgejo/forgejo:15.0.10 environment: - USER_UID=1000 - USER_GID=1000 - FORGEJO__database__DB_TYPE=postgres - FORGEJO__database__HOST=db:5432 - FORGEJO__database__NAME=forgejo - FORGEJO__database__USER=forgejo - FORGEJO__database__PASSWD=change-me-db-password - FORGEJO__security__INSTALL_LOCK=true - FORGEJO__server__ROOT_URL=http://127.0.0.1:3000/ - FORGEJO__server__SSH_PORT=2222 - FORGEJO__actions__ENABLED=true - FORGEJO__actions__DEFAULT_ACTIONS_URL=https://data.forgejo.org restart: unless-stopped volumes: - fj-data:/data ports: - "127.0.0.1:3000:3000" - "127.0.0.1:2222:22" depends_on: - db db: image: postgres:17.11-alpine restart: unless-stopped environment: - POSTGRES_USER=forgejo - POSTGRES_PASSWORD=change-me-db-password - POSTGRES_DB=forgejo volumes: - fj-pg:/var/lib/postgresql/data runner: image: code.forgejo.org/forgejo/runner:13.2.0 user: "0:0" restart: unless-stopped command: ["/bin/sh", "-c", "while [ ! -f /data/.runner ]; do sleep 2; done; exec forgejo-runner daemon --config /data/config.yml"] volumes: - fj-runner:/data - /var/run/docker.sock:/var/run/docker.sock depends_on: - server volumes: fj-data: fj-pg: fj-runner: FORGEJO__actions__ENABLED=true and the default actions URL match the documented defaults and are written out so the file explains itself. Forgejo publishes no latest tag at all, by design, so pinning a full version like 15.0.10 is the normal path. Start it, create an admin and register the runner: docker compose up -d docker compose exec -u git server forgejo admin user create --admin \ --username labadmin --email you@example.com --password "$(openssl rand -hex 12)" \ --must-change-password=false TOKEN=$(docker compose exec -u git server forgejo actions generate-runner-token | tr -d "\r") docker compose exec runner sh -c "cd /data && forgejo-runner generate-config > config.yml \ && sed -i \"s/^ network: .*/ network: fj_default/\" config.yml \ && forgejo-runner register --no-interactive --instance http://server:3000 \ --token $TOKEN --name lab-runner --labels docker:docker://alpine:3.24.2" docker compose restart runner The network: fj_default line puts job containers on the Compose network so they can reach http://server:3000. The runner mounts the Docker socket, which gives it root-level control of the host. Run it on a separate machine if untrusted people can push workflows. GitLab CE with a runner The GitLab Docker install docs ask for an externally reachable hostname and say not to use localhost. The lab mapped gitlab.lab.test to 127.0.0.1 in /etc/hosts and gave the container the same name as a network alias, so the runner and job containers resolve it too: name: gl services: gitlab: image: gitlab/gitlab-ce:19.5.0-ce.0 hostname: gitlab.lab.test restart: unless-stopped shm_size: "256m" environment: GITLAB_ROOT_PASSWORD: ${GITLAB_ROOT_PASSWORD} GITLAB_OMNIBUS_CONFIG: | external_url "http://gitlab.lab.test:8929" registry_external_url "http://gitlab.lab.test:5050" gitlab_rails["gitlab_shell_ssh_port"] = 2224 ports: - "127.0.0.1:8929:8929" - "127.0.0.1:5050:5050" - "127.0.0.1:2224:22" volumes: - gl-config:/etc/gitlab - gl-logs:/var/log/gitlab - gl-data:/var/opt/gitlab networks: default: aliases: - gitlab.lab.test runner: image: gitlab/gitlab-runner:alpine-v19.5.0 restart: unless-stopped volumes: - gl-runner:/etc/gitlab-runner - /var/run/docker.sock:/var/run/docker.sock volumes: gl-config: gl-logs: gl-data: gl-runner: Put GITLAB_ROOT_PASSWORD= with a long random value in a .env file next to it and run docker compose up -d. Without that variable, GitLab writes a generated password to /etc/gitlab/initial_root_password inside the container and deletes it on the first container restart after 24 hours. For the constrained run, these lines were appended to GITLAB_OMNIBUS_CONFIG and the container recreated: # memory-constrained settings from docs.gitlab.com/omnibus/settings/memory_constrained_envs puma["worker_processes"] = 0 sidekiq["concurrency"] = 10 prometheus_monitoring["enable"] = false gitlab_rails["env"] = { "MALLOC_CONF" => "dirty_decay_ms:1000,muzzy_decay_ms:1000" } gitaly["env"] = { "MALLOC_CONF" => "dirty_decay_ms:1000,muzzy_decay_ms:1000", "GITALY_COMMAND_SPAWN_MAX_PARALLEL" => "2" } Then create an instance runner under Admin, CI/CD, Runners (or with POST /api/v4/user/runners), copy the glrt- token and register: docker compose exec runner gitlab-runner register --non-interactive \ --url http://gitlab.lab.test:8929 --token glrt-REPLACE_ME \ --executor docker --docker-image alpine:3.24.2 --docker-network-mode gl_default CI, registry, issues and merge requests GitLab CI and Forgejo Actions Each instance got a hello-ci repository with the same two-step job on alpine:3.24.2. The GitLab version lives in .gitlab-ci.yml: hello: image: alpine:3.24.2 script: - echo "hello from GitLab CI" - cat /etc/alpine-release The pipeline started on push and passed. The job page reported 4 seconds of run time after 1 second in the queue. With the constrained settings, the API reported 2.93 seconds for a rerun. !GitLab CE 19.5.0 job log for job 1 in root/hello-ci, status Passed. The log shows the runner pulling alpine:3.24.2, fetching the repository, running echo hello from GitLab CI and printing 3.24.2, then Job succeeded. The sidebar shows a duration of 4 seconds and runner number 1, lab-runner. Forgejo reads workflows from .forgejo/workflows/, and falls back to .github/workflows/ when that folder is missing: on: [push] jobs: hello: runs-on: docker steps: - run: echo "hello from Forgejo Actions" - run: cat /etc/alpine-release runs-on: docker matches the label given at registration. The run passed, and the Actions page reported about 1 second for the job. !Forgejo 15.0.10 Actions run page for labadmin/hello-ci, workflow hello.yml triggered by the add workflow commit. The hello job succeeded. Log sections show Set up job with runner version v13.2.0 starting image alpine:3.24.2 on network fj_default, then the echo step printing hello from Forgejo Actions, the cat step printing 3.24.2, and Complete job. The syntax looks like GitHub Actions on purpose. The Forgejo Actions docs say: "Forgejo Actions is designed to be familiar to users of GitHub Actions, but it is not designed to be compatible." Expect small edits when you bring workflows over. GitLab CI uses its own YAML format, so moving between the two means a rewrite either way. Registry, issues and code review Both ship a container registry. On GitLab it is a separate bundled service that turns on when you set registry_external_url, here on port 5050. The requirements page lists a domain and TLS certificates for it in real use. The lab used plain HTTP on a loopback name, which Docker accepts because it treats 127.0.0.0/8 as an insecure registry by default. For any other address, Docker refuses plain HTTP unless the registry is listed under insecure-registries, so put both registries behind HTTPS before you push from another machine. On Forgejo, the registry is part of the package registry and lives on the main web port, so the image name is 127.0.0.1:3000/labadmin/alpine-copy:3.24.2. Both pushes of the same Alpine image succeeded with the same digest, sha256:7cefa58b..., after a docker login with an access token. Issues and code review worked the same way on both. An issue, a branch, a commit and a pull or merge request with Closes #1 took a handful of API calls. Both linked the issue and showed the passing pipeline on the review page. !GitLab CE merge request Tweak README, number 1, open from branch readme-tweak into main. The description says Closes number 1, a Pipeline number 3 passed widget shows a green check, approval is optional, and Ready to merge offers a Merge button with Delete source branch checked. The sidebar lists Lab issue: check CI badge under work items it closes. GitLab wraps that core in more DevOps menus. The CE project sidebar in the screenshots groups them under Plan, Code, Build, Secure, Deploy, Operate, Monitor and Analyze. Forgejo keeps the GitHub-style layout: issues, pull requests, projects, packages, wiki and Actions as tabs on the repository. !Forgejo 15.0.10 pull request Tweak README number 2 in labadmin/hello-ci, open, wanting to merge 1 commit from readme-tweak into main. The comment says Closes number 1. A checks box reads All checks were successful with hello push successful in 1s, the pull request can be merged automatically, and a Create merge commit button is shown. Migrations, upgrades and backups Migrating a real repository Both instances imported https://github.com/plausible/community-edition over HTTPS as plain Git. Forgejo returned from POST /api/v1/repos/migrate in 0.4 seconds with 31 commits and 11,425 KB on disk. GitLab 19.5.0 refused at first. On a fresh install, import_sources was an empty list, so import by URL was off and the API returned 403. Enabling git and github under Admin, Settings, General, Import and export settings fixed it, but the same request kept returning 403 for about three minutes before it succeeded. After that, the import finished within a few seconds, with the same 31 commits and 11.4 MB. For a move away from GitLab, the Forgejo migrator can also bring issues, labels, milestones, releases and merge requests when you give it a GitLab access token. The Codeberg migration docs list GitLab among the services with metadata support. Forgejo uses one number space for issues and pull requests, so merge request numbers shift on the way in. Forgejo pull request #1790 offsets them by the highest issue number, and pull request #10077, merged in November 2025, rewrites !N references in comments to match. Upgrades and backups GitLab ships a minor release every month on the third Thursday, patch releases twice a month and one major release a year, per its maintenance policy. Security fixes reach the current release and the two before it. Jumps between versions must pass through required upgrade stops. For GitLab 19 those are 19.2, 19.5, 19.8 and 19.11, so the tested 19.5.0 is itself a stop. The Docker upgrade docs say to back up at least the database and the secrets file, upgrade the runner to the same version, change the image tag, then run docker compose pull and docker compose up -d. The upgrade path page says to let background migrations finish before the next stop. Forgejo releases quarterly, with one LTS a year. The release schedule gives 15.0 LTS support until July 15, 2027, while 16.0 reaches end of life on October 29, 2026. The FAQ says major upgrades need a manual check, which is why the project publishes no latest tag. Inside a line, the 15 and 15.0 tags follow the newest minor and patch release. For backups, GitLab: docker compose exec gitlab gitlab-backup create ran in 24.6 seconds and wrote a 16.2 MB tar to /var/opt/gitlab/backups/. It ended with a warning that gitlab.rb and gitlab-secrets.json are not in the archive. The warning adds: "You will need these files to restore a backup." Copy both separately. Forgejo: docker compose exec -u git -w /tmp server forgejo dump --type tar.gz --file /tmp/forgejo-dump.tar.gz ran in 0.4 seconds and wrote a 15.6 MB archive with the repositories, packages, forgejo-db.sql and app.ini. That app.ini holds SECRET_KEY, INTERNAL_TOKEN and JWT_SECRET, so treat the dump file as a secret. Copy either archive off the box and test a restore on a scratch instance. Licensing, federation and which to pick Licensing and federation The GitLab LICENSE file puts the code outside the ee/ directory under the MIT Expat license, with the docs under CC BY-SA 4.0. Code in ee/ falls under the EE license, which allows production use only with a GitLab subscription. The gitlab-ce image is the MIT edition, and the 19.5.0 API reported "enterprise":false. The Forgejo FAQ says versions 9.0 and later are GPL v3 or later, versions up to 8.0 were MIT, and the project is not AGPL. Federation through ForgeFed is a stated Forgejo goal. The FAQ says: "Federation is under active development, and is considered experimental." It warns of breaking changes that can burn the domain for future federation. The config cheat sheet defaults [federation] ENABLED to false, and the ActivityPub user endpoint returned 404 on the 17.0.0 lab install. Federated stars were the first user-facing feature, per a FOSDEM 2025 talk. Treat federation as a future feature, not a reason to switch today. Which one to pick Pick Forgejo when: - The server is a small VPS, a homelab box or anything with 1 to 4 GB of RAM. The whole stack idled under 300 MiB here. - You want GitHub-style repos, pull requests, packages and Actions with little upkeep, and a quarterly release rhythm with a yearly LTS. - You prefer a copyleft license and a community project whose domains are held by the non-profit Codeberg e.V. Pick GitLab CE when: - You want one integrated DevOps tool: mature CI/CD with stages, a merge request flow and planning in the same UI. - You can give it 8 GB of RAM or more, or accept the constrained profile and its trade-offs at about 2.4 GiB. - You may want paid EE features later. The memory-constrained docs page says you can always upgrade from CE to EE. For a solo developer or a small team, Forgejo covers the same daily Git work. On this host it used about a thirtieth of the idle RAM of default GitLab. Add an Uptime Kuma monitor on the login page either way, and if you want push-to-deploy on top, connect the repo to Coolify. FAQ Resources and CI Why does GitLab use so much RAM when idle? It runs many services in one container, and on this 8 vCPU host the ten Ruby processes held about 1 GB each. A default 19.5.0 container idled at 8,657.7 MiB (about 8.5 GiB) here, close to the 8.452 GB that a user reported on a fresh container in the GitLab forum thread on high RAM usage. The memory-constrained settings brought it to about 2.4 GiB. Can GitLab run on a 4 GB VPS? It can start with the constrained profile, which idled at 2,466.5 MiB in this run. GitLab documents 8 GB as the floor for constrained single-node installs and 16 GB as the baseline. In a forum thread about memory after the 17.0 upgrade, a reply calls 4 GB the absolute minimum and recommends 8 GB. Can Forgejo Actions run GitHub Actions workflows unchanged? Not always. The Forgejo docs say Actions is designed to be familiar to GitHub users but not designed to be compatible, so expect small edits. Forgejo also falls back to .github/workflows/ when .forgejo/workflows/ is missing. Migration, licensing and federation Can you migrate from GitLab to Forgejo with issues and merge requests? Yes, with a GitLab access token in the migration form. Merge requests become pull requests numbered after the highest issue number, and !N references in comments are rewritten since pull request #10077. Cross-repository references are still tracked in issue #11332. Is Forgejo licensed under the AGPL? No. The Forgejo FAQ says GPL v3 or later from version 9.0, MIT up to 8.0, and that switching to AGPL or EUPL was proposed without agreement. Can Forgejo instances federate with each other yet? Only experimentally. Federation is off by default, the FAQ calls it experimental, and moderation and access control are still missing. The 2025 FOSDEM talk marked federated stars as done and listed following, comments and pull requests across instances as roadmap items. Originally published on DeployLark: GitLab CE vs Forgejo: Self-Hosted Git on Docker, Measured

    1 comment
  9. Self-Host Plausible Community Edition with Docker Plausible Community Edition is a self-hosted, cookie-free analytics stack. The same product family powers Plausible Cloud, and CE is the free, AGPL-licensed release you run yourself. On October 18, 2026, the analytics repository had about 29,500 stars, and the community-edition compose repo had about 2,900. This guide installs CE v3.2.1 from the official Compose files, pins every image tag, puts the dashboard on 127.0.0.1, and confirms a real pageview on a lab site. The Umami Docker and PostgreSQL guide covers a lighter Postgres-only stack. Plausible CE adds ClickHouse for events and ships a different feature set from Cloud. For a broader app platform on the same VPS, see the Coolify install guide. TL;DR: - Clone plausible/community-edition at tag v3.2.1, set BASE_URL and a 64-byte SECRET_KEY_BASE in .env, and pin Postgres and ClickHouse to exact tags in compose.override.yml. - Bind the app to 127.0.0.1:8000 and put Nginx Proxy Manager or Caddy in front with HTTPS. Keep BASE_URL equal to the public URL. - Open the dashboard, create the first account, add a site, paste the generated script into the site <head>, and confirm a pageview on the dashboard. - Expect about 2 GB of RAM for a calm ClickHouse setup. CPU needs SSE 4.2 or NEON. - Upgrade by checking out a newer CE tag and running docker compose up -d. Back up Postgres with pg_dump and keep the ClickHouse volumes. Table of contents What CE gives you, and what stays on Cloud Feature and licence differences The self-hosting docs compare Cloud and CE in one table. The points that matter for a home lab or a small team are: - You own the server: installs, upgrades, backups, capacity and uptime are yours. - CE releases twice a year. Cloud ships features continuously. - Marketing funnels, user journeys, ecommerce revenue goals, SSO and the sites API are Cloud-only. - Bot filtering on CE is the basic User-Agent and referrer-spam path. Cloud adds data-center IP filtering and a broader bot model. - Premium human support is Cloud-only. Self-hosting is community-supported only, per the self-hosting docs. - CE is AGPL-3.0 (or later). Cloud is a paid subscription that funds the project. If you modify CE and offer it as a network service, AGPL requires you to share the corresponding source with users of that service. Read the licence before you ship a public SaaS on top of CE. Hardware and CPU requirements The CE README asks for Docker, Docker Compose, a CPU with SSE 4.2 or NEON (ClickHouse needs it), and at least 2 GB of RAM so ClickHouse and Plausible stay clear of OOM kills. The compose file mounts low-resource ClickHouse settings for small servers. On the lab host used for this guide (8 vCPUs with SSE 4.2, Debian 13), the three containers used about 710 MB of RAM after the first pageviews: about 450 MB for Plausible, 185 MB for ClickHouse and 80 MB for Postgres. Install the official Compose stack Clone the repo and set .env The install path is the community-edition repository, not a hand-rolled compose file. Clone a specific tag so the ClickHouse config files match the app: git clone -b v3.2.1 --single-branch https://github.com/plausible/community-edition plausible-ce cd plausible-ce Create .env with the two required variables from the configuration wiki: touch .env chmod 600 .env echo "BASE_URL=https://plausible.example.com" >> .env echo "SECRET_KEY_BASE=$(openssl rand -base64 48)" >> .env echo "HTTP_PORT=8000" >> .env BASE_URL has no default. It drives link generation and WebSocket origin checks. Set it to the URL people will type in the browser, including https:// once a reverse proxy terminates TLS. For a local evaluation, the README tip is BASE_URL=http://localhost:8000 (or any free port). The lab run used http://127.0.0.1:8000. SECRET_KEY_BASE also has no default. It must be at least 64 bytes. openssl rand -base64 48 produces a 64-character value that meets that rule. Runtime config raises if the key is missing: SECRET_KEY_BASE configuration option is required. A short key fails later with cookie store expects conn.secret_key_base to be at least 64 bytes, which matches discussion #3516 and issue #5612. Pin image tags and bind to localhost Upstream compose.yml at v3.2.1 uses ghcr.io/plausible/community-edition:v3.2.1, postgres:16-alpine and clickhouse/clickhouse-server:24.12-alpine. The last two float. On October 18, 2026, those tags resolved to PostgreSQL 16.15 and ClickHouse 24.12.6.70. Put the exact tags in compose.override.yml so future docker compose pull calls stay on known builds, and publish the app only on the loopback address as the reverse-proxy wiki shows: services: plausible_db: image: postgres:16.15-alpine plausible_events_db: image: clickhouse/clickhouse-server:24.12.6.70-alpine plausible: image: ghcr.io/plausible/community-edition:v3.2.1 ports: - "127.0.0.1:8000:8000" The override file is the supported place for local changes. It survives git pull of a new CE tag better than editing compose.yml. The stack looks like this once it is up: !Diagram of the Plausible Community Edition Docker Compose stack. A visitor browser sends POST /api/event to the plausible container (CE v3.2.1 on 127.0.0.1:8000). A second browser reaches the dashboard over HTTP. The plausible container uses plausible_db (PostgreSQL 16.15) and plausible_events_db (ClickHouse 24.12.6.70). An optional reverse proxy (Caddy or Nginx Proxy Manager) terminates TLS. Named volumes are db-data, event-data, event-logs and plausible-data. Start it: docker compose up -d docker compose ps curl --head http://127.0.0.1:8000 On a warm host with images already pulled, Postgres and ClickHouse became healthy in under a minute, and /register returned HTTP 200 about 15 seconds after the app container started. An Uptime Kuma HTTP monitor on /login is enough to notice when the dashboard stops answering. The first visit is the registration page: !Plausible Community Edition registration page titled Register your Plausible CE account, with a five-step progress bar starting at Register, and a form for full name, email, password and confirm password, plus a Create my account button. Password hint says Min 12 characters. Create that first account right away. Default registration is invite-only after the first user (DISABLE_REGISTRATION defaults to invite_only in the wiki). The first account owns the instance. Default database credentials in the compose file are postgres / postgres. Change them for anything exposed beyond a private lab by setting POSTGRES_PASSWORD and a matching DATABASE_URL in .env (see the configuration wiki). Put HTTPS in front Reverse proxy layout From CE 2.1.2 onward, Plausible can request Let's Encrypt certificates itself when HTTP_PORT=80 and HTTPS_PORT=443 are published. Behind an existing proxy, keep HTTP_PORT=8000, bind 127.0.0.1:8000, and terminate TLS on the proxy. That is the layout this guide tested. A minimal Caddy config from the wiki is: plausible.example.com { reverse_proxy localhost:8000 } Nginx Proxy Manager works the same way: proxy host to http://127.0.0.1:8000, force SSL, and enable WebSockets so /live/websocket stays up for the live dashboard. The same 127.0.0.1 binding pattern shows up in the Vaultwarden HTTPS guide and the Paperless-ngx Compose guide. The wiki's Nginx sample proxies that path with Upgrade and Connection headers. Keep BASE_URL on the public hostname Whatever you pick, BASE_URL must match the public URL. With a wrong host, the dashboard HTML can load while the LiveView WebSocket returns 403. Issue #205 shows the log line Could not check origin for Phoenix.Socket transport when the browser origin and BASE_URL disagree. After you change .env, run docker compose up -d so the container recreates. A plain docker compose restart does not reload env vars. Add a site and confirm a pageview Install the tracking script After registration, the wizard asks for a domain and timezone, then shows a site-specific script. Paste it into the <head> of the site. On CE v3.2.1 the snippet looks like this shape (the pa-… filename is unique per site): <!-- Privacy-friendly analytics by Plausible --> <script async src="https://plausible.example.com/js/pa-xxxxxxxx.js"></script> <script> window.plausible=window.plausible||function(){(plausible.q=plausible.q||[]).push(arguments)},plausible.init=plausible.init||function(i){plausible.o=i||{}}; plausible.init() </script> !Plausible CE Install Plausible step showing the Script tab, a COPY box with the tracking snippet that loads a pa- script from the instance URL, optional measurements for outbound links, file downloads and form submissions, and a Verify Script installation button. Optional checkboxes turn on outbound-link, file-download and form-submission measurements. The new script updates those choices from the dashboard. Legacy snippets that used data-domain still work. The script update guide covers migration. The script's event endpoint is taken from BASE_URL (it posts to {BASE_URL}/api/event). Sites that only allowlist their own analytics host in Content-Security-Policy need that origin in connect-src, or an endpoint override in plausible.init as shown in discussion #6126. Confirm the first pageview Open the site in a normal browser and watch the CE dashboard for the domain. The lab run added example.test, served a static page with the generated snippet, and recorded pageviews. After four accepted events, the dashboard showed 4 unique visitors, 4 total pageviews and the / path under Top pages: !Plausible CE dashboard for example.test showing 4 current visitors, Unique visitors 4, Total visits 4, Total pageviews 4, Views per visit 1, Bounce rate 100 percent, a today graph with a spike to 4, Top sources Direct / None, and Top pages /. Two checks that catch false starts: 1. The script ignores localhost and 127.0.0.1 by design. The browser console prints Ignoring Event: localhost. That matches community-edition issue #92 and the troubleshooting docs. Test on a real hostname (a /etc/hosts entry is enough in a lab). 2. A 202 from POST /api/event is not always a stored event. The troubleshooting docs say to look for x-plausible-dropped: 1 when a visit is filtered. The lab posts that used a normal browser User-Agent and an X-Forwarded-For address returned 202 without that header, and ClickHouse held four rows in plausible_events_db.events_v2. Upgrades and backups Upgrades The upgrade wiki recommends pinning a full patch tag such as v3.2.1. Security fixes are not backported, so plan to move forward. v3.2.1 itself is a security release that removes an exposed /storybook endpoint (CVE-2026-8467). General steps for a patch or minor bump: cd plausible-ce git fetch origin v3.2.1:v3.2.1 git checkout v3.2.1 # keep your .env and compose.override.yml docker compose up -d Read the release notes before every major bump. Some releases change ClickHouse config files in the community-edition repo, which is why the checkout step matters. Backups Postgres holds users and site settings. ClickHouse holds events. The Upgrade PostgreSQL wiki shows a pg_dump path that doubles as a backup: docker compose stop plausible docker compose exec plausible_db sh -c "pg_dump -U postgres plausible_db > plausible_db.bak" docker compose cp plausible_db:plausible_db.bak ./plausible_db.bak docker compose start plausible Keep copies of the ClickHouse volumes (event-data, and event-logs if you care about server logs) with your volume backup tool. There is no separate CE wiki page that ships a one-line ClickHouse dump. Restoring across major ClickHouse versions needs extra care, so keep the image tag pin in compose.override.yml. Also back up .env. Losing SECRET_KEY_BASE logs everyone out of the dashboard. Site data in Postgres and ClickHouse stays, as ruslandoga noted when rotating the key. CE can also send account activation, password resets and optional reports when SMTP or a mail provider adapter is configured. The configuration wiki lists SMTP_HOST_ADDR, MAILER_EMAIL and the Postmark, Mailgun, Mandrill and SendGrid variables. Without SMTP, local accounts still work when ENABLE_EMAIL_VERIFICATION stays at its default false. Those providers were not exercised in the lab run. FAQ Setup and resources How much RAM does Plausible CE need? The CE README recommends at least 2 GB so ClickHouse and Plausible avoid OOM kills. The lab stack with the bundled low-resource ClickHouse config used about 710 MB of RAM after the first pageviews. Builds and heavy queries need more headroom than idle stats. Why does the dashboard load but live data stay empty? BASE_URL usually does not match the URL in the browser. The HTML can still load while /live/websocket fails origin checks. Set BASE_URL to the public URL, then recreate the container with docker compose up -d. See issue #205. Why is SECRET_KEY_BASE required, and how long must it be? The configuration wiki requires it and asks for at least 64 bytes. Generate one with openssl rand -base64 48. A missing key stops startup. A short key breaks cookie sessions with cookie store expects conn.secret_key_base to be at least 64 bytes. Tracking and HTTPS Why does the browser say "Ignoring Event: localhost"? The tracker refuses localhost and loopback hosts so local development noise stays out of production stats. Use a real hostname for the test site, or a hosts-file entry that is not localhost. Maintainer replies in issue #92 call out the same console warning. Which Cloud features are missing from CE? Per the self-hosting docs: marketing funnels, user journeys, ecommerce revenue goals, SSO and the sites API. Bot filtering is also simpler on CE, and there is no premium support channel. How do you put HTTPS in front of CE? Either publish ports 80 and 443 and let CE request certificates, or bind 127.0.0.1:8000 and terminate TLS on Caddy or Nginx Proxy Manager. Keep BASE_URL on the https:// URL in both cases. The reverse-proxy wiki has sample configs. Originally published on DeployLark: Self-Host Plausible Community Edition with Docker

    1 reaction · 1 comment
  10. YouTube · · YouTube description · Alberto IA · plausible/analytics

    10 Repositorios de GitHub que Reemplazan Suscripciones Caras (100% Open Source) ¿Cuánto dinero se te va cada mes pagando suscripciones de software que apenas usas al máximo? Calendly, DocuSign, Miro, Airtable, Zapier, Firebase o Google Fotos parecen baratos por separado, pero juntos representan un impuesto silencioso de más de $2,400 dólares al año sobre tu trabajo. En este video analizamos en pizarra 10 repositorios de código abierto (Open Source) en GitHub que juntos suman casi 800,000 estrellas y que reemplazan directamente a las plataformas SaaS más caras del mercado. Veremos cómo funciona su arquitectura paso a paso, qué problema resuelven y cuál es la realidad técnica de autohospedarlos (Self-Hosting) en tu propio servidor. ⏱️ MARCAS DE TIEMPO (CAPÍTULOS): 00:00 El Impuesto Silencioso de las Suscripciones SaaS ($2,400/año) 01:05 #10 Documenso (Alternativa Open Source a DocuSign) 01:40 #9 Cal.com (Alternativa Open Source a Calendly) 02:13 #8 PostHog (Alternativa a Amplitude y Mixpanel) 02:55 #7 Penpot (Alternativa Open Source a Figma) 03:32 #6 NocoDB (Alternativa Open Source a Airtable) 04:08 #5 Coolify (Alternativa a Vercel, Netlify y Heroku) 04:38 #4 Excalidraw (Alternativa a Miro y Lucidchart) 05:16 #3 Supabase (Alternativa Open Source a Google Firebase) 05:48 #2 n8n (Alternativa a Zapier y Make para Automatización e IA) 06:23 #1 Immich (Alternativa privada a Google Fotos e iCloud) 07:03 Menciones Honoríficas (Plausible, AppFlowy, Listmonk, Ollama) y la Verdad del Self-Hosting 🔗 REPOSITORIOS MENCIONADOS EN EL VIDEO: • #10 Documenso: documenso/documenso • #9 Cal.com: calcom/cal.com • #8 PostHog: PostHog/posthog • #7 Penpot: penpot/penpot • #6 NocoDB: nocodb/nocodb • #5 Coolify: coollabsio/coolify • #4 Excalidraw: excalidraw/excalidraw • #3 Supabase: supabase/supabase • #2 n8n: n8n-io/n8n • #1 Immich: immich-app/immich ⚡ MENCIONES EXTRA: • Plausible Analytics: plausible/analytics • AppFlowy: AppFlowy-IO/AppFlowy • Listmonk: knadh/listmonk • Ollama: ollama/ollama 🔔 Suscríbete al canal para más tutoriales prácticos sobre inteligencia artificial, automatización, código abierto y laboratorios virtuales explicados paso a paso: 💣 Suscríbete aquí 👉 youtube.com #GitHub #OpenSource #SelfHosting #n8n #Supabase #Docker #Automatizacion #InteligenciaArtificial #SoftwareLibre #AlbertoIA

    16 likes · 1 comment · 1,103 views

Achievements

Awards earned by the repositories plausible owns. Select an award to embed its badge.

Gold
01st place finishes
Silver
02nd place finishes
Bronze
13rd place finishes
Awarded repositories
1Owned by plausible now

Repositories

Ordered by gold, then silver, then bronze.

  1. analyticsBest: 3rd by stars, 340 stars001

Every award

Top-three finishes of these repositories in completed trending days and weeks, newest first.

  1. analytics

A repository earns an award for finishing first, second or third in a completed trending day or week, ranked by new stars, new forks or pull request authors. Awards follow a repository through renames and transfers and count toward its current owner. Weeks run Monday to Sunday, UTC.