[{"data":1,"prerenderedAt":-1},["ShallowReactive",2],{"$fw5IxC5_v8Tqp9UtKP-pLnzBd5YJvkw3yqQxmNW0JYr8":3},{"posts":4,"total":95,"page":96,"limit":97},[5,76],{"id":6,"title":7,"teaser":8,"body":9,"slug":10,"date":11,"tags":12},"6cc5d2e4-f5df-4de9-95ed-c4b8538c87ca","Running 12 services on two VPS boxes in Germany - my self-hosted infrastructure","I run my entire digital life on two Contabo VPS servers in Germany. Personal site, photography portfolio, business site, email, password vault, analytics, monitoring - all of it. No AWS. No Vercel.…","\u003Cp>I run my entire digital life on two Contabo VPS servers in Germany. Personal site, photography portfolio, business site, email, password vault, analytics, monitoring - all of it. No AWS. No Vercel. No managed anything. Just Docker, Traefik, and a lot of evenings spent getting things right.\u003C\u002Fp>\u003Cp>This is not a tutorial. This is a walkthrough of what I actually built, why I built it this way, and what I learned along the way.\u003C\u002Fp>\u003Ch2>The servers\u003C\u002Fh2>\u003Cp>Two VPS boxes at Contabo, both in Germany. That matters to me - European hosting, European jurisdiction, GDPR by default.\u003C\u002Fp>\u003Cp>VPS1 is the jump server. It runs GitLab and a self-hosted GitHub Actions runner. Every deployment to production goes through this machine. It is the gatekeeper.\u003C\u002Fp>\u003Cp>VPS2 is where everything lives. At last count, it runs north of 50 Docker containers across 13 distinct services. Traefik v3 sits at the front, handling routing, SSL termination, and automatic Let's Encrypt certificate renewal for every domain.\u003C\u002Fp>\u003Cp>Both servers were recently upgraded from Ubuntu 20.04 to 22.04 - a process I documented across 12 sessions in the contabo-infrastructure repo. Ubuntu 20.04 had reached end of life, and running an EOL operating system under a stack this size was not something I was comfortable with.\u003C\u002Fp>\u003Ch2>The stack at a glance\u003C\u002Fh2>\u003Cp>Here is what runs on VPS2, broken down by service:\u003C\u002Fp>\u003Cp>\u003Cstrong>madsnorgaard.net\u003C\u002Fstrong> - my personal site. A Nuxt 3 SSR frontend that pulls content from two separate headless CMS backends simultaneously. Writing, projects, CV, and about pages come from a headless Drupal 11 instance via JSON:API. Photography and stories come from photo.madsnorgaard.net via the WordPress REST API. One frontend, two content sources. IBM Plex Mono, dark terminal aesthetic.\u003C\u002Fp>\u003Cp>\u003Cstrong>drupal.madsnorgaard.net\u003C\u002Fstrong> - headless Drupal 11. This is where I write articles, manage project pages, and maintain the content that feeds into the Nuxt frontend. It runs its own Docker stack with MySQL, Redis for caching, and Apache Solr for search. The site itself is built from the minimal install profile - no unnecessary modules, no bloat. Composer manages everything. GitHub Actions handles CI\u002FCD with PHP CodeSniffer checking custom modules and themes on every push.\u003C\u002Fp>\u003Cp>\u003Cstrong>photo.madsnorgaard.net\u003C\u002Fstrong> - the photography backend. WordPress 6.x running as a headless REST API for my documentary photography archive. Custom post types for photos, stories, and projects. Custom taxonomies for series and subjects. A security plugin that blocks XML-RPC, removes user enumeration endpoints, rate-limits the API, and adds security headers. The Nuxt frontend at madsnorgaard.net consumes this API alongside Drupal's JSON:API - that dual-source architecture is one of the things I am most pleased with in this whole setup.\u003C\u002Fp>\u003Cp>\u003Cstrong>fenixnordic.solutions\u003C\u002Fstrong> - the marketing site for Fenix Nordic Solutions, the side agency Phoenix and I run together. Nuxt 3 static-generated, bilingual English and Danish, with a dark Nordic editorial design. Custom cursor with ember particles, magnetic button effects, scroll reveal animations. It started as a Drupal site but I rebuilt it as a pure Nuxt frontend. The old Drupal artefacts are still in the repo - a future cleanup task.\u003C\u002Fp>\u003Cp>\u003Cstrong>theazanianprepper.online\u003C\u002Fstrong> - a WordPress site on Docker with Traefik.\u003C\u002Fp>\u003Cp>\u003Cstrong>cosycreator.online\u003C\u002Fstrong> - a Payload CMS v2 project on Docker with Traefik.\u003C\u002Fp>\u003Cp>\u003Cstrong>Rocket.Chat\u003C\u002Fstrong> - self-hosted team communication. Running MongoDB 6.0, upgraded March 2026.\u003C\u002Fp>\u003Cp>\u003Cstrong>Traefik v3\u003C\u002Fstrong> - the reverse proxy that ties it all together. Every service on VPS2 routes through Traefik. It handles SSL termination with automatic Let's Encrypt certificates, forces HTTPS on all traffic, and routes requests to the right container based on domain name. The dashboard is accessible internally via SSH tunnel - no public exposure. The configuration is public on GitHub. Adding a new service is a matter of Docker Compose labels - no nginx configs to edit, no manual certificate management.\u003C\u002Fp>\u003Cp>\u003Cstrong>Monitoring\u003C\u002Fstrong> - Grafana, Prometheus, Loki, AlertManager, cAdvisor, Node Exporter, and Blackbox Exporter. Four provisioned dashboards covering site uptime, infrastructure metrics, logs, and Traefik request analytics. Blackbox Exporter probes eight sites for uptime and SSL certificate expiry. AlertManager routes critical alerts to email via Mailgun. And then there is the webhook bridge - a custom Python service that automatically creates GitHub issues when an alert fires and closes them when the alert resolves. That one took some debugging to get the deduplication right, but it means I never miss an infrastructure problem.\u003C\u002Fp>\u003Cp>\u003Cstrong>Mail\u003C\u002Fstrong> - docker-mailserver 14 with Postfix, Dovecot, and Rspamd. Roundcube webmail at webmail.madsnorgaard.net. traefik-certs-dumper handles the TLS certificates. fail2ban protects against brute force attempts. I scored 10\u002F10 on mail-tester.com with this setup - SPF, DKIM, DMARC, rDNS, all of it configured correctly. Self-hosted email that actually works and does not end up in spam folders.\u003C\u002Fp>\u003Cp>\u003Cstrong>Vaultwarden\u003C\u002Fstrong> - a Bitwarden-compatible password vault. This one gets special treatment in the deployment pipeline. No auto-deploy. Manual approval required every time. Contabo snapshot mandatory before any change. When the service that stores every password you own goes down because of a bad deploy, you are locked out of everything. I treat it accordingly.\u003C\u002Fp>\u003Cp>\u003Cstrong>Plausible CE v2\u003C\u002Fstrong> - self-hosted analytics replacing Google Analytics across all my sites. Privacy-respecting, no cookies, no consent banners needed. The Grafana monitoring stack pulls data from Plausible via an Infinity datasource, so I can see analytics alongside infrastructure metrics in the same dashboard.\u003C\u002Fp>\u003Ch2>The deployment architecture\u003C\u002Fh2>\u003Cp>This is where it gets interesting. Every service deploys through the same pipeline, but the mechanism is not what you might expect.\u003C\u002Fp>\u003Cp>Each service has its own GitHub repository. When I push to main, GitHub Actions runs CI checks - linting, CodeSniffer, Composer validation, whatever is relevant for that project. If the checks pass, the workflow fires a \u003Ccode>repository_dispatch\u003C\u002Fcode> event to the contabo-infrastructure repo.\u003C\u002Fp>\u003Cp>The contabo-infrastructure repo has a self-hosted GitHub Actions runner on VPS1. When it receives the dispatch event, it checks out the source repo, rsyncs the relevant files to VPS2 via SSH, builds the Docker images on VPS2, and restarts the containers. VPS2 does not need GitHub SSH access - all files are pushed from the runner on VPS1.\u003C\u002Fp>\u003Cp>The result: I push code, and a few minutes later it is live. No manual SSH. No FTP. No cowboy deployments. The contabo-infrastructure repo has seen 315 production deployments at the time of writing.\u003C\u002Fp>\u003Cp>Critical services like Vaultwarden break this pattern deliberately. They require manual workflow triggers with reviewer approval. You do not auto-deploy your password vault.\u003C\u002Fp>\u003Ch2>The monitoring layer\u003C\u002Fh2>\u003Cp>I spent a lot of time on observability because running this many services without it is asking for trouble.\u003C\u002Fp>\u003Cp>Prometheus scrapes metrics from every container via cAdvisor, from the host via Node Exporter, and from external endpoints via Blackbox Exporter. Loki aggregates logs from all containers via Promtail. Grafana displays everything across four provisioned dashboards.\u003C\u002Fp>\u003Cp>The alert rules are straightforward: CPU warning at 85 percent for five minutes, critical at 95 percent for two minutes. Memory warning at 85 percent. Disk warning at 80 percent, critical at 90 percent. Container down if not seen for two minutes.\u003C\u002Fp>\u003Cp>When an alert fires, AlertManager sends an email via Mailgun and the webhook bridge creates a GitHub issue in the contabo-infrastructure repo with all the alert details. When the alert resolves, the bridge comments on the issue and closes it. The entire incident lifecycle is tracked in GitHub Issues without me lifting a finger.\u003C\u002Fp>\u003Cp>There is a caveat with cAdvisor - it is pinned to v0.47.2. The latest version causes roughly 12.8 percent constant CPU overhead, which on a VPS running this many containers is unacceptable. I update the version deliberately after testing, not automatically.\u003C\u002Fp>\u003Cp>Loki recently completed the upgrade path from 1.6.1 all the way to 3.0.0 - stepping through 2.0.x and 2.9.x along the way, with verified Contabo snapshots at each stage. It was a careful process but the result is a modern log aggregation stack that I no longer have to worry about being left behind on.\u003C\u002Fp>\u003Ch2>Self-hosted email - the achievement I am most proud of\u003C\u002Fh2>\u003Cp>Getting email right is notoriously difficult. Getting it right on a self-hosted stack with perfect deliverability is the kind of challenge that makes most people give up and use a managed service.\u003C\u002Fp>\u003Cp>The stack is docker-mailserver 14 - Postfix for SMTP, Dovecot for IMAP, Rspamd for spam filtering. Roundcube provides webmail. traefik-certs-dumper pulls TLS certificates from the Traefik ACME store so the mail server uses the same Let's Encrypt certificates as everything else. fail2ban watches for brute force attempts with custom jail configuration for Docker subnet awareness.\u003C\u002Fp>\u003Cp>DNS records include SPF, DKIM (generated by the setup script), DMARC, MX, and a PTR record configured through Contabo's panel. Every piece has to be correct or your mail ends up in spam.\u003C\u002Fp>\u003Cp>I ran the full suite through mail-tester.com and scored 10\u002F10. That is SPF aligned, DKIM signed, DMARC enforced, reverse DNS matching, no blacklists, proper HELO hostname. The works.\u003C\u002Fp>\u003Cp>Using mads@madsnorgaard.net as my primary email address, hosted on my own server, with full control over every aspect of the stack - that aligns with everything I believe about digital sovereignty.\u003C\u002Fp>\u003Ch2>Why self-host everything\u003C\u002Fh2>\u003Cp>I wrote previously about saying goodbye to PayPal and American service providers. This infrastructure is the practical expression of that conviction.\u003C\u002Fp>\u003Cp>Every service I self-host is a service where I control the data, the configuration, the uptime, and the terms. Nobody can freeze my account. Nobody can change the pricing. Nobody can decide my data belongs to them for training purposes. Nobody can shut down the product and leave me scrambling for alternatives.\u003C\u002Fp>\u003Cp>It costs time. Significantly more time than paying for managed services. The Ubuntu upgrade across both servers took 12 documented sessions. The mail server setup took a solid week of evenings. The monitoring stack has been an ongoing project for months.\u003C\u002Fp>\u003Cp>But the trade-off is sovereignty. I know exactly what runs on my servers. I know exactly where my data lives. I can audit every line of configuration. And when something breaks - and things do break - I can fix it myself without waiting for a support ticket response from a company that may or may not care about my specific problem.\u003C\u002Fp>\u003Ch2>The numbers\u003C\u002Fh2>\u003Cp>Across VPS2: 13 distinct service stacks. North of 50 Docker containers. Eight sites monitored for uptime. Four Grafana dashboards provisioned from git. 315 production deployments via the contabo-infrastructure pipeline. 65 release tags on the madsnorgaard.net repo alone. 12 release tags on the drupal.madsnorgaard.net repo. 38 release tags on the fenixnordic.solutions repo. 10\u002F10 mail-tester.com score.\u003C\u002Fp>\u003Cp>All of it running on two VPS boxes in a German data centre. No cloud provider lock-in. No vendor dependencies I cannot replace. Open source by default.\u003C\u002Fp>\u003Ch2>What is next\u003C\u002Fh2>\u003Cp>There are things I want to improve. The fenixnordic.solutions repo still has old Drupal artefacts that should be cleaned out. I want to add more Plausible integration into the Grafana dashboards. The cAdvisor version pinning needs revisiting - newer releases may have resolved the CPU overhead issue that forced me to stay on v0.47.2.\u003C\u002Fp>\u003Cp>And I keep thinking about documenting this whole setup more publicly. Not just the individual repos - several of those are already public - but the architecture as a whole. How the pieces connect. How the deployment pipeline works end to end. How monitoring feeds back into the development workflow via GitHub Issues.\u003C\u002Fp>\u003Cp>Because the thing I hear most often when I share this work is: \"I did not know you could do all that on two VPS boxes.\" You can. It takes time, patience, and a willingness to read documentation at midnight. But you absolutely can.\u003C\u002Fp>\u003Cp>Self-hosted whenever I can. European where it makes sense. Open source by default.\u003C\u002Fp>\u003Cp>\u003Cem>Infrastructure repos: \u003C\u002Fem>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmadsnorgaard\u002Ftraefik\">\u003Cem>traefik\u003C\u002Fem>\u003C\u002Fa>\u003Cem> · \u003C\u002Fem>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmadsnorgaard\u002Fplausible\">\u003Cem>plausible\u003C\u002Fem>\u003C\u002Fa>\u003Cem> · \u003C\u002Fem>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmadsnorgaard\u002Ffenixnordic.solutions\">\u003Cem>fenixnordic.solutions\u003C\u002Fem>\u003C\u002Fa>\u003Cem> · \u003C\u002Fem>\u003Ca href=\"https:\u002F\u002Fgithub.com\u002Fmadsnorgaard\u002Fmadsnorgaard.net\">\u003Cem>madsnorgaard.net\u003C\u002Fem>\u003C\u002Fa>\u003C\u002Fp>","running-12-services-two-vps-boxes-germany-my-self-hosted-infrastructure","2026-04-03T11:01:42+00:00",[13,16,19,22,25,28,31,34,37,40,43,46,49,52,55,58,61,64,67,70,73],{"id":14,"name":15,"slug":15},"d965487f-3728-4202-86de-5b2a421c60a4","Self-hosting",{"id":17,"name":18,"slug":18},"cd4d8de4-8189-439a-92d1-52d8b9178351","Docker",{"id":20,"name":21,"slug":21},"b036641d-390a-413b-b911-5684b9cf2860","Traefik",{"id":23,"name":24,"slug":24},"db8b4a3f-d438-4953-94ef-71a9e8a77cea","VPS",{"id":26,"name":27,"slug":27},"2fc2f328-ec87-4cae-b18d-c0dba26d3938","Contabo",{"id":29,"name":30,"slug":30},"9ce82c64-b167-4baa-870e-b17ca303f357","infrastructure",{"id":32,"name":33,"slug":33},"49f2de4c-0b5c-4736-9470-1ff09e7a57b5","DevOps",{"id":35,"name":36,"slug":36},"be2d7dd2-5cf1-4b35-89d8-a8e456b3ad50","monitoring",{"id":38,"name":39,"slug":39},"9b49265e-11c3-497d-9dc6-fcf72529d6d5","Grafana",{"id":41,"name":42,"slug":42},"bfac572a-a9d6-48a5-9204-ae809f58e232","Prometheus",{"id":44,"name":45,"slug":45},"877c06ef-54af-4b16-83dd-d0dba7ccaad9","digital sovereignty",{"id":47,"name":48,"slug":48},"ec7b1417-6d0a-4518-b726-4bd2a0764356","open source",{"id":50,"name":51,"slug":51},"98c95e6b-edb6-4a31-a5a7-83531bb0b35b","Linux",{"id":53,"name":54,"slug":54},"85d7d938-8e2e-4d27-902e-6c08d10928bd","Nuxt",{"id":56,"name":57,"slug":57},"1ab21e16-a352-4411-b33d-b423729af017","Drupal",{"id":59,"name":60,"slug":60},"be16e000-cc9c-4531-8bda-4a2908eae6fd","WordPress",{"id":62,"name":63,"slug":63},"618fcaff-3861-4bdc-9a6e-29fde8d30d95","email",{"id":65,"name":66,"slug":66},"d1d49fd0-0dc5-4d6f-ad78-2fe03b559a2a","Vaultwarden",{"id":68,"name":69,"slug":69},"1e2953cf-bab4-42ea-95e5-11182922a268","Plausible",{"id":71,"name":72,"slug":72},"89071faf-ca5c-42d6-822e-555a2051d86e","CI\u002FCD",{"id":74,"name":75,"slug":75},"4f98c9bf-dee5-404a-8b6f-17c4c1e88da5","GitHub Actions",{"id":77,"title":78,"teaser":79,"body":80,"slug":81,"date":82,"tags":83},"f353d484-15a4-441a-b7d9-5c2166261943","Getting Omarchy Running: What I Actually Did","Look, I just installed Omarchy on my laptop. Fresh. And yeah, it's amazing out of the box, but let's be honest - you're going to want your own tools. This isn't a generic tutorial. This is what I…","\u003Cp>Look, I just installed Omarchy on my laptop. Fresh. And yeah, it's amazing out of the box, but let's be honest - you're going to want your own tools. This isn't a generic tutorial. This is what I actually did to get from \"nice Linux desktop\" to \"ready to work.\"\u003C\u002Fp>\u003Ch2>What is Omarchy, really?\u003C\u002Fh2>\u003Cp>DHH made it. The Ruby on Rails guy. He got fed up with Apple's App Store nonsense and decided to build his own Linux distribution. Not just scripts - a full operating system that looks nothing like the desktop environments you're used to.\u003C\u002Fp>\u003Cp>Everything happens via keyboard. I mean EVERYTHING. Your mouse basically retires. Sounds weird? It is at first. But then you realize you're flying through tasks.\u003C\u002Fp>\u003Cp>37signals (DHH's company) is moving their entire dev team to this. Over three years, they're ditching Macs completely. Why? Rails tests run twice as fast on Linux. Docker works natively. No virtualization overhead.\u003C\u002Fp>\u003Cp>The shortcuts you need to remember RIGHT NOW:\u003C\u002Fp>\u003Cul>\u003Cli>\u003Ccode>Super + Space\u003C\u002Fcode> - Launch anything\u003C\u002Fli>\u003Cli>\u003Ccode>Super + Alt + Space\u003C\u002Fcode> - The Omarchy Menu (your control panel)\u003C\u002Fli>\u003Cli>\u003Ccode>Super + Return\u003C\u002Fcode> - Terminal\u003C\u002Fli>\u003Cli>\u003Ccode>Super + Esc\u003C\u002Fcode> - Reload everything\u003C\u002Fli>\u003C\u002Ful>\u003Cp>Got it? Good. Let's actually install stuff.\u003C\u002Fp>\u003Ch2>Installing Essential Development Tools\u003C\u002Fh2>\u003Ch3>Setting Up Zsh and Oh My Zsh\u003C\u002Fh3>\u003Cp>Omarchy doesn't come with zsh by default, but it's easy to install and configure:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\"># Install zsh\nsudo pacman -S zsh\n\n# Add zsh to valid shells\ncommand -v zsh | sudo tee -a \u002Fetc\u002Fshells\n\n# Install Oh My Zsh\nsh -c \"$(curl -fsSL https:\u002F\u002Fraw.githubusercontent.com\u002Fohmyzsh\u002Fohmyzsh\u002Fmaster\u002Ftools\u002Finstall.sh)\"\n\n# Set zsh as default shell (if chsh doesn't work, use the workaround below)\nsudo usermod -s \u002Fusr\u002Fbin\u002Fzsh $USER\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Cstrong>If shell changing doesn't work\u003C\u002Fstrong>, add this to your \u003Ccode>~\u002F.bashrc\u003C\u002Fcode> as a workaround:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\">echo 'exec zsh' &gt;&gt; ~\u002F.bashrc\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Installing Oh My Zsh Plugins\u003C\u002Fh3>\u003Cp>Enhance your terminal experience with these essential plugins:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\"># Autosuggestions (suggests commands as you type)\ngit clone https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-autosuggestions ${ZSH_CUSTOM:-~\u002F.oh-my-zsh\u002Fcustom}\u002Fplugins\u002Fzsh-autosuggestions\n\n# Syntax highlighting (colors your commands)\ngit clone https:\u002F\u002Fgithub.com\u002Fzsh-users\u002Fzsh-syntax-highlighting.git ${ZSH_CUSTOM:-~\u002F.oh-my-zsh\u002Fcustom}\u002Fplugins\u002Fzsh-syntax-highlighting\n\n# Enable plugins - quick one-liner method\nsed -i 's\u002Fplugins=(git)\u002Fplugins=(git zsh-autosuggestions zsh-syntax-highlighting sudo colored-man-pages command-not-found)\u002F' ~\u002F.zshrc\n\n# Reload configuration\nsource ~\u002F.zshrc\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Cstrong>Plugin features:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cstrong>zsh-autosuggestions\u003C\u002Fstrong> - Press → to accept suggestions\u003C\u002Fli>\u003Cli>\u003Cstrong>zsh-syntax-highlighting\u003C\u002Fstrong> - Red = invalid command, green = valid\u003C\u002Fli>\u003Cli>\u003Cstrong>sudo\u003C\u002Fstrong> - Double-tap ESC to add sudo to previous command\u003C\u002Fli>\u003Cli>\u003Cstrong>colored-man-pages\u003C\u002Fstrong> - Colorful, readable man pages\u003C\u002Fli>\u003C\u002Ful>\u003Ch3>Installing IDEs and Editors\u003C\u002Fh3>\u003Ch4>VSCode\u003C\u002Fh4>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\">yay -S visual-studio-code-bin\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>Or use the Omarchy Menu: \u003Ccode>Super + Alt + Space\u003C\u002Fcode> → Install → Editor → VSCode\u003C\u002Fp>\u003Ch4>Setting Default Editor\u003C\u002Fh4>\u003Cp>After installing your preferred editor, set it as default:\u003C\u002Fp>\u003Col>\u003Cli>Press \u003Ccode>Super + Alt + Space\u003C\u002Fcode>\u003C\u002Fli>\u003Cli>Navigate to Setup → Defaults\u003C\u002Fli>\u003Cli>Edit the UWSM defaults file\u003C\u002Fli>\u003Cli>Save and press \u003Ccode>Super + Esc\u003C\u002Fcode> to reload\u003C\u002Fli>\u003C\u002Fol>\u003Ch3>Installing Development Tools\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\"># Install ddev (Docker-based development environment)\nyay -S ddev-bin\n\n# Install all at once if you prefer\nyay -S visual-studio-code-bin ddev-bin slack-desktop discord\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Installing Claude Code\u003C\u002Fh3>\u003Cp>Claude Code is an AI-powered coding assistant that works directly in your terminal:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\"># Recommended: Native installer\ncurl -fsSL https:\u002F\u002Fclaude.ai\u002Finstall.sh | bash\n\n# Alternative: via npm\nnpm install -g @anthropic-ai\u002Fclaude-code\n\n# Verify installation\nclaude doctor\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Cstrong>First-time setup:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\">cd ~\u002Fyour-project\nclaude\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>On first run, you'll authenticate through your browser using either Claude Max or Anthropic Console.\u003C\u002Fp>\u003Cp>\u003Cstrong>Note:\u003C\u002Fstrong> Claude Code requires either a Claude Max subscription or API credits. Max is usually more economical for regular use.\u003C\u002Fp>\u003Ch2>Managing Installed Applications\u003C\u002Fh2>\u003Ch3>Finding Installed Packages\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\"># Search for specific packages\npacman -Q | grep -i \"search-term\"\n\n# List all installed packages\npacman -Q\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Removing Unwanted Applications\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\"># Remove package and unused dependencies\nsudo pacman -Rs package-name\n\n# Example: Remove specific apps\nsudo pacman -Rs 1password-beta 1password-cli\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Using the Omarchy Menu\u003C\u002Fh3>\u003Cp>The easiest way to manage apps:\u003C\u002Fp>\u003Col>\u003Cli>Press \u003Ccode>Super + Alt + Space\u003C\u002Fcode>\u003C\u002Fli>\u003Cli>Navigate to Remove\u003C\u002Fli>\u003Cli>Browse and select apps to uninstall\u003C\u002Fli>\u003C\u002Fol>\u003Ch2>Configuring Multiple Keyboard Layouts\u003C\u002Fh2>\u003Cp>If you work in multiple languages, you'll want to switch between keyboard layouts easily:\u003C\u002Fp>\u003Cp>\u003Cstrong>Edit Hyprland configuration:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\">vim ~\u002F.config\u002Fhypr\u002Fhyprland.conf\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Cstrong>Add\u002Fmodify the input section:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext\">input {\n    kb_layout = us,dk\n    kb_variant = \n    kb_model =\n    kb_options = grp:alt_shift_toggle\n    # ... other input settings\n}\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Cp>\u003Cstrong>Switch layouts:\u003C\u002Fstrong> Press \u003Ccode>Alt + Shift\u003C\u002Fcode>\u003C\u002Fp>\u003Cp>\u003Cstrong>Alternative switching options:\u003C\u002Fstrong>\u003C\u002Fp>\u003Cul>\u003Cli>\u003Ccode>grp:win_space_toggle\u003C\u002Fcode> - Super + Space\u003C\u002Fli>\u003Cli>\u003Ccode>grp:caps_toggle\u003C\u002Fcode> - CapsLock toggles\u003C\u002Fli>\u003Cli>\u003Ccode>grp:ctrl_shift_toggle\u003C\u002Fcode> - Ctrl + Shift\u003C\u002Fli>\u003C\u002Ful>\u003Cp>\u003Cstrong>Apply changes:\u003C\u002Fstrong> Press \u003Ccode>Super + Esc\u003C\u002Fcode> to reload Hyprland\u003C\u002Fp>\u003Ch2>Package Management Tips\u003C\u002Fh2>\u003Cp>Omarchy uses a combination of package managers:\u003C\u002Fp>\u003Ch3>pacman (Official Arch packages)\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\"># Update system\nsudo pacman -Syu\n\n# Install package\nsudo pacman -S package-name\n\n# Remove package\nsudo pacman -R package-name\n\n# Remove with dependencies\nsudo pacman -Rs package-name\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>yay (AUR helper)\u003C\u002Fh3>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\"># Search AUR\nyay -Ss search-term\n\n# Install from AUR\nyay -S package-name\n\n# Update AUR packages\nyay -Syu\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Omarchy Menu\u003C\u002Fh3>\u003Cp>The GUI way: \u003Ccode>Super + Alt + Space\u003C\u002Fcode> gives you access to:\u003C\u002Fp>\u003Cul>\u003Cli>\u003Cstrong>Install\u003C\u002Fstrong> → Package (Arch repos)\u003C\u002Fli>\u003Cli>\u003Cstrong>Install\u003C\u002Fstrong> → AUR (AUR packages)\u003C\u002Fli>\u003Cli>\u003Cstrong>Install\u003C\u002Fstrong> → Editor, Style, Font (curated lists)\u003C\u002Fli>\u003Cli>\u003Cstrong>Remove\u003C\u002Fstrong> → Uninstall applications\u003C\u002Fli>\u003Cli>\u003Cstrong>Update\u003C\u002Fstrong> → System updates\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>Troubleshooting Common Issues\u003C\u002Fh2>\u003Ch3>Permission Errors with npm\u003C\u002Fh3>\u003Cp>Never use \u003Ccode>sudo npm install -g\u003C\u002Fcode>. Instead, configure npm properly:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\">mkdir ~\u002F.npm-global\nnpm config set prefix '~\u002F.npm-global'\necho 'export PATH=~\u002F.npm-global\u002Fbin:$PATH' &gt;&gt; ~\u002F.zshrc\nsource ~\u002F.zshrc\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Shell Won't Change\u003C\u002Fh3>\u003Cp>If \u003Ccode>chsh\u003C\u002Fcode> doesn't work, use the workaround:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\">echo 'exec zsh' &gt;&gt; ~\u002F.bashrc\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Missing Text Editors\u003C\u002Fh3>\u003Cp>Omarchy ships with Neovim but not nano. Install if needed:\u003C\u002Fp>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\">sudo pacman -S nano\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch3>Bluetooth Keyboard at Boot\u003C\u002Fh3>\u003Cp>Full-disk encryption requires a wired keyboard (or 2.4GHz wireless) to enter the password at startup. Bluetooth keyboards won't work at this stage.\u003C\u002Fp>\u003Ch2>Essential Omarchy Workflows\u003C\u002Fh2>\u003Ch3>File Management\u003C\u002Fh3>\u003Cp>Omarchy includes a file manager accessible through the app launcher (\u003Ccode>Super + Space\u003C\u002Fcode>).\u003C\u002Fp>\u003Ch3>Screenshots\u003C\u002Fh3>\u003Cp>Use the built-in screenshot tools via hotkeys or the Omarchy Menu.\u003C\u002Fp>\u003Ch3>Installing Fonts\u003C\u002Fh3>\u003Cp>\u003Ccode>Super + Alt + Space\u003C\u002Fcode> → Install → Style → Font\u003C\u002Fp>\u003Ch3>Theming\u003C\u002Fh3>\u003Cp>Omarchy comes beautifully themed, but you can customize: \u003Ccode>Super + Alt + Space\u003C\u002Fcode> → Style\u003C\u002Fp>\u003Ch2>Keeping Your System Updated\u003C\u002Fh2>\u003Cpre>\u003Ccode class=\"language-plaintext language-bash\"># Update Omarchy-specific packages\nomarchy-update-git\n\n# Update all system packages\nsudo pacman -Syu\n\n# Update AUR packages\nyay -Syu\n\n# Or use the Omarchy Menu\n# Super + Alt + Space → Update\n\u003C\u002Fcode>\u003C\u002Fpre>\u003Ch2>Useful Resources\u003C\u002Fh2>\u003Cul>\u003Cli>\u003Cstrong>Official Documentation:\u003C\u002Fstrong> https:\u002F\u002Flearn.omacom.io\u002F\u003C\u002Fli>\u003Cli>\u003Cstrong>Omarchy Website:\u003C\u002Fstrong> https:\u002F\u002Fomarchy.org\u002F\u003C\u002Fli>\u003Cli>\u003Cstrong>Community Discord:\u003C\u002Fstrong> Join for installation help and troubleshooting\u003C\u002Fli>\u003Cli>\u003Cstrong>GitHub Repository:\u003C\u002Fstrong> https:\u002F\u002Fgithub.com\u002Fbasecamp\u002Fomarchy\u003C\u002Fli>\u003C\u002Ful>\u003Ch2>Conclusion\u003C\u002Fh2>\u003Cp>Omarchy provides an excellent foundation for a modern development environment. With the tools and configurations covered in this guide, you'll have a fully customized system tailored to your workflow. The keyboard-driven approach may take some getting used to, but once mastered, it significantly boosts productivity.\u003C\u002Fp>\u003Cp>Remember: everything in Omarchy is designed to be accessible via keyboard shortcuts. Learn the basics (\u003Ccode>Super + Space\u003C\u002Fcode>, \u003Ccode>Super + Alt + Space\u003C\u002Fcode>, \u003Ccode>Super + Return\u003C\u002Fcode>), and you'll quickly discover why so many developers are making the switch.\u003C\u002Fp>\u003Cp>Happy coding on Omarchy!\u003C\u002Fp>\u003Chr>\u003Cp>\u003Cem>Have questions or suggestions for this guide? Feel free to reach out or leave a comment below.\u003C\u002Fem>\u003C\u002Fp>","getting-omarchy-running-what-i-actually-did","2025-10-07T07:05:45+00:00",[84,87,90,91,92],{"id":85,"name":86,"slug":86},"b9e7e7c2-917e-4693-b3d5-0db82a7d80ca","omarchy",{"id":88,"name":89,"slug":89},"7867e670-e264-4621-b4fc-cc0a8c4b15dd","operating system",{"id":47,"name":48,"slug":48},{"id":50,"name":51,"slug":51},{"id":93,"name":94,"slug":94},"901060fc-ba5a-4f54-9ea5-3a5fbf19e565","the alternative",0,1,20]