[{"content":"ProHomeLab is open to authors who want to share their knowledge and practical experience in the world of homelabbing.\nIf you\u0026rsquo;re building your own home infrastructure, experimenting with servers, virtualization, containers, networking, NAS, monitoring, or automation, I\u0026rsquo;d love to feature your experience on the site.\nIt doesn\u0026rsquo;t matter how big your home lab is. What matters isn\u0026rsquo;t the number of servers in the rack, but real experience, interesting solutions, and knowledge worth sharing with others.\nWhat you can write about # The topics ProHomeLab covers are fairly broad. For example:\nbuilding and growing a homelab; server hardware and its configuration; Proxmox, virtualization, and containerization; Docker, Podman, and Kubernetes; NAS, ZFS, Ceph, and storage systems; home networking, VLANs, routing, and firewalls; reverse proxies, DNS, and SSL/TLS; monitoring, logging, and backups; home infrastructure automation; self-hosted applications and services; information security; Linux and other server operating systems; migrating services and infrastructure; breakdowns of interesting projects and architectural decisions; practical how-tos and troubleshooting; your own experiments and their results. This is far from an exhaustive list. If you have an interesting topic that isn\u0026rsquo;t on this list, write to me anyway.\nWhat makes for interesting material # First and foremost - practice.\nYou don\u0026rsquo;t have to write a fundamental guide spanning dozens of pages. A good article can cover a single specific task, even a narrow one: how you configured something, what problem you ran into, what options you tried, and what solution you ultimately settled on as the best for your case.\nMaterial where the author explains not just \u0026ldquo;how to do it\u0026rdquo; but also \u0026ldquo;why I did it this way\u0026rdquo; is especially valuable.\nWriting about mistakes is fine, even encouraged. A failed experiment, a non-obvious problem, or an unexpected limitation sometimes turns out far more useful than a perfectly polished tutorial. I\u0026rsquo;ve had plenty of those myself\u0026hellip;\nRequirements for submissions # Articles are only accepted in Markdown format.\nIdeally, the material should:\nbe written independently and with minimal AI assistance (I know pretty much everyone uses AI to some degree these days, but trust me, I can recognize AI phrasing); be based on the author\u0026rsquo;s real experience - this is the most important thing; contain concrete examples and/or technical details; let the reader reproduce the described actions, if it\u0026rsquo;s a how-to; not just be a translation or retelling of someone else\u0026rsquo;s article - if it is a translation or retelling, which is fine, a link to the original source is mandatory; not contain hidden advertising or promotional placements without prior agreement; not be about circumventing blocks and restrictions imposed by Roskomnadzor. If the article contains commands, config files, or code, they should be formatted using standard Markdown.\nThere\u0026rsquo;s no strict length requirement. A short but substantive article is better than a long wall of filler text.\nBefore publication, the material may be edited for language, structure, and formatting. The technical content, the author\u0026rsquo;s approach, style, and voice will not be changed.\nWhat to provide along with the article # To get published, you\u0026rsquo;ll need to provide:\nThe article in Markdown format. The author name that will be displayed on the site. An author avatar - preferably a good-quality square image. A short author bio - optional. For example, what you do and what interests you in the homelab world - this will be shown in the list of authors (but, of course, only with your consent). Links to your site, GitHub, Forgejo, or other projects - if you\u0026rsquo;d like them listed in your profile. The avatar and name are needed to properly credit authorship of the material on the site.\nNo commercial interest whatsoever # ProHomeLab is a non-commercial project.\nI don\u0026rsquo;t make money from the site (right now I only have expenses - hosting and the .com domain name) and I don\u0026rsquo;t plan to monetize it - at least, there are no such plans for now. There are no paid posts, paid link placements, or any hidden commercial terms for authors.\nSo this invitation to collaborate is exactly that - an invitation to share knowledge and experience, not an attempt to get some commercial benefit out of an author.\nThere\u0026rsquo;s no catch here: if you have interesting homelabbing material you want to share, I simply want to, and can, give it a platform and introduce it to other enthusiasts.\nThat said, if an article mentions specific products, services, or companies, that\u0026rsquo;s not a problem in itself. What matters is that the material reflects the author\u0026rsquo;s real experience, rather than being disguised advertising.\nHow to submit material # The simplest option is to reach out to me and send the article in Markdown along with author information.\nIf the material is already in a Git repository, you can just send a link to the repository or the specific file.\nThe way you send the material isn\u0026rsquo;t important - what matters is that the source text can be obtained in Markdown without losing formatting.\nAuthorship # Every published article retains its creator\u0026rsquo;s authorship.\nThe author\u0026rsquo;s name is listed directly on the publication, and if you have relevant links, I can add your profile or links to your own projects.\nI\u0026rsquo;m not trying to turn ProHomeLab into either a media outlet or a soulless knowledge base - in the 21st century, neither is really possible anyway.\nWhy this matters # Homelab isn\u0026rsquo;t just about hardware and software. It\u0026rsquo;s above all about sharing experience.\nEvery project has its own quirks: someone built a server out of an old office PC, someone built a full-blown cluster, someone automated dozens of services, and someone found an elegant solution to a problem that stumped the best minds around.\nMaybe your experience is exactly what will help someone save time, avoid a mistake, or simply inspire them to build their own homelab.\n","date":"August 9, 2026","externalUrl":null,"permalink":"/en/posts/author-collaboration/","section":"Posts","summary":"ProHomeLab is open to authors who want to share their knowledge and practical experience in the world of homelabbing.\nIf you’re building your own home infrastructure, experimenting with servers, virtualization, containers, networking, NAS, monitoring, or automation, I’d love to feature your experience on the site.\nIt doesn’t matter how big your home lab is. What matters isn’t the number of servers in the rack, but real experience, interesting solutions, and knowledge worth sharing with others.\nWhat you can write about # The topics ProHomeLab covers are fairly broad. For example:\n","title":"Inviting authors to collaborate","type":"posts"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/categories/","section":"Categories","summary":"","title":"Categories","type":"categories"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/tags/postiz/","section":"Tags","summary":"","title":"Postiz","type":"tags"},{"content":" Postiz: trying to automate YouTube, VK, and RuTube - and why only one out of three actually works # For obvious reasons, at some point I ended up with three platforms where I upload video - YouTube as the main one, plus VK and RuTube for the part of the audience for whom that-which-must-not-be-named doesn\u0026rsquo;t work. Uploading the same video by hand three times is the kind of task that gets old fast, believe me, I know what I\u0026rsquo;m talking about - so I decided to look into a self-hosted solution for automatic publishing. My choice landed on Postiz - an open-source post scheduler (AGPL-3.0 license), a self-hosted alternative to Buffer/Hootsuite/Later, with claimed support for three dozen platforms at once.\nOn paper it all sounded great: write a post once, pick the platforms and time - and Postiz distributes the publication on schedule by itself. In practice things turned out a bit less smooth than the project\u0026rsquo;s own marketing materials suggest. YouTube connected without surprises, aside from the issue of not being able to select Russia as the channel\u0026rsquo;s country of registration. But that\u0026rsquo;s not the app\u0026rsquo;s problem - it\u0026rsquo;s just today\u0026rsquo;s reality with Google. VK took some fiddling, but it all ended in failure. And RuTube\u0026hellip; well, let\u0026rsquo;s take it step by step.\nWhat Postiz is # Postiz is an open-source tool for scheduling and automatically posting to social media. Essentially, a self-hosted alternative to Buffer/Hootsuite/Later - only without a monthly subscription and with full control over your data, which, for my homelab blog, sounds like the only right path. The project officially claims support for more than 30 platforms - X, Instagram, LinkedIn, TikTok, Facebook, Threads, Discord, Slack, YouTube, VK, and so on.\nBut here\u0026rsquo;s something you\u0026rsquo;ll run into almost immediately: not all of those thirty-plus platforms are supported equally well. A small caveat: of course, I haven\u0026rsquo;t tested every platform listed in the app. Some services have a full \u0026ldquo;Connect\u0026rdquo; button right in the interface. Some only work through a Public API, with no way to click through the UI. And some platforms, as it turns out, simply aren\u0026rsquo;t present in Postiz at all - whatever the landing page says. RuTube is exactly such a case.\nSetting up Postiz # The first important point - the developers themselves explicitly ask you not to drag a docker-compose.yml from someone\u0026rsquo;s article (which, it turns out, includes mine), but to grab it from the canonical repository:\ngit clone https://github.com/gitroomhq/postiz-docker-compose The logic is understandable in principle - services, images, the set of env variables, and container functionality change from release to release, and data from an article can quickly go stale. From there, docker compose up -d from the canonical repository brings up Postiz, Postgres, Redis, and Temporal (which handles queues and publication scheduling here) as a single stack.\nI took this compose file as a base, but before running it on my setup, I tidied it up to match my usual requirements and habits - just like with other services in my homelab: I replaced Docker volumes with bind mounts, moved all secrets (JWT_SECRET, DB passwords, social media keys) into a separate .env, and added Traefik labels right away, just commented out, because at the moment Traefik on my setup runs in a separate LXC container.\nNext comes the most tedious part - environment variables. There are a lot of them, really a lot, but for a home lab with a Traefik reverse proxy, only a handful are truly critical:\nVariable What it does DATABASE_URL Postgres connection string REDIS_URL Redis connection (queues, cache) JWT_SECRET a long random string for signing sessions FRONTEND_URL the address at which the browser sees the Postiz frontend NEXT_PUBLIC_BACKEND_URL the address at which the browser sees the Postiz backend BACKEND_INTERNAL_URL the address at which the frontend (SSR) reaches the backend inside the network/container MAIN_URL optional, for absolute links in email notifications. If not set, FRONTEND_URL is used An external Postgres instead of the container out of the box # One point where I immediately departed from the canonical compose file - Postgres. In the official repository it\u0026rsquo;s brought up as a local container next to Postiz itself, but I already have a separate Postgres 16 server at the appropriate address - the same one that serves Forgejo, Authentik, and a bunch of other services, set up precisely so I don\u0026rsquo;t end up with a separate DB container for every self-hosted service.\nThe official system requirements documentation calls for PostgreSQL version 14 or newer, so version 16 clears that bar with room to spare - no need to upgrade or spin up a separate instance. An external Postgres for Postiz is an officially supported scenario; the developers specifically mention it in the system requirements as an option that just requires more memory for the Postiz process itself on the host.\nTechnically, this means the postiz-postgres service simply doesn\u0026rsquo;t exist in my compose file, and DATABASE_URL points directly at the external host:\nDATABASE_URL=\u0026#34;postgresql://postiz:password@x.x.x.x:5432/postiz\u0026#34; The only nuance is that the database and user on the external server need to be created in advance, manually (I do this through pgAdmin): Postiz will run migrations automatically on first start, but it won\u0026rsquo;t create the database from scratch - it needs it to already exist. Temporal, meanwhile, kept its own Postgres - it has a separate database with its own requirements (extensions, schema), so I left its local container alone and didn\u0026rsquo;t move it anywhere.\nThere\u0026rsquo;s one important point here: FRONTEND_URL is used as the base for the OAuth redirect - it\u0026rsquo;s the address that YouTube, VK, and all the other platforms will call back to after authorization. If Postiz sits behind Traefik (as in my case) at https://postiz.domain.ru, then FRONTEND_URL needs to be exactly that address, character for character, with no extra slashes or typos - otherwise the OAuth callback simply gets lost somewhere on the way to your homelab. Plus, Postiz sets secure cookies by itself, which means it won\u0026rsquo;t really work properly without proper HTTPS - a self-signed certificate won\u0026rsquo;t help here, you need a real one; in my case it\u0026rsquo;s all handled through Traefik and Let\u0026rsquo;s Encrypt as usual.\nThe Traefik labels are added to the compose file exactly the same way as in all my other articles about Docker services behind a reverse proxy - a router on websecure, TLS, redirect from HTTP to HTTPS, all that.\nTo avoid scattering the final file across the whole article - here it is in full, with all the edits described above (bind mount, secrets moved into .env, external Postgres, commented-out Traefik labels):\nservices: postiz: image: ghcr.io/gitroomhq/postiz-app:latest container_name: postiz restart: always environment: # === Required Settings MAIN_URL: \u0026#39;https://${POSTIZ_DOMAIN}\u0026#39; FRONTEND_URL: \u0026#39;https://${POSTIZ_DOMAIN}\u0026#39; NEXT_PUBLIC_BACKEND_URL: \u0026#39;https://${POSTIZ_DOMAIN}/api\u0026#39; JWT_SECRET: \u0026#39;${POSTIZ_JWT_SECRET}\u0026#39; DATABASE_URL: \u0026#39;postgresql://${POSTIZ_DB_USER}:${POSTIZ_DB_PASSWORD}@${POSTIZ_DB_HOST}:${POSTIZ_DB_PORT}/${POSTIZ_DB_NAME}\u0026#39; REDIS_URL: \u0026#39;redis://postiz-redis:6379\u0026#39; BACKEND_INTERNAL_URL: \u0026#39;http://localhost:3000\u0026#39; TEMPORAL_ADDRESS: \u0026#34;temporal:7233\u0026#34; IS_GENERAL: \u0026#39;true\u0026#39; DISABLE_REGISTRATION: \u0026#39;false\u0026#39; RUN_CRON: \u0026#39;true\u0026#39; # === Storage Settings STORAGE_PROVIDER: \u0026#39;local\u0026#39; UPLOAD_DIRECTORY: \u0026#39;/uploads\u0026#39; NEXT_PUBLIC_UPLOAD_DIRECTORY: \u0026#39;/uploads\u0026#39; # === Cloudflare (R2) Settings # STORAGE_PROVIDER: \u0026#39;cloudflare\u0026#39; # CLOUDFLARE_ACCOUNT_ID: \u0026#39;${CLOUDFLARE_ACCOUNT_ID}\u0026#39; # CLOUDFLARE_ACCESS_KEY: \u0026#39;${CLOUDFLARE_ACCESS_KEY}\u0026#39; # CLOUDFLARE_SECRET_ACCESS_KEY: \u0026#39;${CLOUDFLARE_SECRET_ACCESS_KEY}\u0026#39; # CLOUDFLARE_BUCKETNAME: \u0026#39;${CLOUDFLARE_BUCKETNAME}\u0026#39; # CLOUDFLARE_BUCKET_URL: \u0026#39;https://your-bucket-url.r2.cloudflarestorage.com/\u0026#39; # CLOUDFLARE_REGION: \u0026#39;auto\u0026#39; # === Social Media API Settings (fill in as you connect platforms) X_API_KEY: \u0026#39;${X_API_KEY:-}\u0026#39; X_API_SECRET: \u0026#39;${X_API_SECRET:-}\u0026#39; LINKEDIN_CLIENT_ID: \u0026#39;${LINKEDIN_CLIENT_ID:-}\u0026#39; LINKEDIN_CLIENT_SECRET: \u0026#39;${LINKEDIN_CLIENT_SECRET:-}\u0026#39; REDDIT_CLIENT_ID: \u0026#39;${REDDIT_CLIENT_ID:-}\u0026#39; REDDIT_CLIENT_SECRET: \u0026#39;${REDDIT_CLIENT_SECRET:-}\u0026#39; GITHUB_CLIENT_ID: \u0026#39;${GITHUB_CLIENT_ID:-}\u0026#39; GITHUB_CLIENT_SECRET: \u0026#39;${GITHUB_CLIENT_SECRET:-}\u0026#39; BEEHIIVE_API_KEY: \u0026#39;${BEEHIIVE_API_KEY:-}\u0026#39; BEEHIIVE_PUBLICATION_ID: \u0026#39;${BEEHIIVE_PUBLICATION_ID:-}\u0026#39; THREADS_APP_ID: \u0026#39;${THREADS_APP_ID:-}\u0026#39; THREADS_APP_SECRET: \u0026#39;${THREADS_APP_SECRET:-}\u0026#39; FACEBOOK_APP_ID: \u0026#39;${FACEBOOK_APP_ID:-}\u0026#39; FACEBOOK_APP_SECRET: \u0026#39;${FACEBOOK_APP_SECRET:-}\u0026#39; YOUTUBE_CLIENT_ID: \u0026#39;${YOUTUBE_CLIENT_ID:-}\u0026#39; YOUTUBE_CLIENT_SECRET: \u0026#39;${YOUTUBE_CLIENT_SECRET:-}\u0026#39; TIKTOK_CLIENT_ID: \u0026#39;${TIKTOK_CLIENT_ID:-}\u0026#39; TIKTOK_CLIENT_SECRET: \u0026#39;${TIKTOK_CLIENT_SECRET:-}\u0026#39; PINTEREST_CLIENT_ID: \u0026#39;${PINTEREST_CLIENT_ID:-}\u0026#39; PINTEREST_CLIENT_SECRET: \u0026#39;${PINTEREST_CLIENT_SECRET:-}\u0026#39; DRIBBBLE_CLIENT_ID: \u0026#39;${DRIBBBLE_CLIENT_ID:-}\u0026#39; DRIBBBLE_CLIENT_SECRET: \u0026#39;${DRIBBBLE_CLIENT_SECRET:-}\u0026#39; DISCORD_CLIENT_ID: \u0026#39;${DISCORD_CLIENT_ID:-}\u0026#39; DISCORD_CLIENT_SECRET: \u0026#39;${DISCORD_CLIENT_SECRET:-}\u0026#39; DISCORD_BOT_TOKEN_ID: \u0026#39;${DISCORD_BOT_TOKEN_ID:-}\u0026#39; SLACK_ID: \u0026#39;${SLACK_ID:-}\u0026#39; SLACK_SECRET: \u0026#39;${SLACK_SECRET:-}\u0026#39; SLACK_SIGNING_SECRET: \u0026#39;${SLACK_SIGNING_SECRET:-}\u0026#39; MASTODON_URL: \u0026#39;https://mastodon.social\u0026#39; MASTODON_CLIENT_ID: \u0026#39;${MASTODON_CLIENT_ID:-}\u0026#39; MASTODON_CLIENT_SECRET: \u0026#39;${MASTODON_CLIENT_SECRET:-}\u0026#39; # === OAuth \u0026amp; Authentik Settings (uncomment if you decide to add SSO like Vaultwarden) # NEXT_PUBLIC_POSTIZ_OAUTH_DISPLAY_NAME: \u0026#39;Authentik\u0026#39; # NEXT_PUBLIC_POSTIZ_OAUTH_LOGO_URL: \u0026#39;https://raw.githubusercontent.com/walkxcode/dashboard-icons/master/png/authentik.png\u0026#39; # POSTIZ_GENERIC_OAUTH: \u0026#39;false\u0026#39; # POSTIZ_OAUTH_URL: \u0026#39;https://auth.domain.ru\u0026#39; # POSTIZ_OAUTH_AUTH_URL: \u0026#39;https://auth.domain.ru/application/o/authorize/\u0026#39; # POSTIZ_OAUTH_TOKEN_URL: \u0026#39;https://auth.domain.ru/application/o/token/\u0026#39; # POSTIZ_OAUTH_USERINFO_URL: \u0026#39;https://auth.domain.ru/application/o/userinfo/\u0026#39; # POSTIZ_OAUTH_CLIENT_ID: \u0026#39;${POSTIZ_OAUTH_CLIENT_ID}\u0026#39; # POSTIZ_OAUTH_CLIENT_SECRET: \u0026#39;${POSTIZ_OAUTH_CLIENT_SECRET}\u0026#39; # POSTIZ_OAUTH_SCOPE: \u0026#34;openid profile email\u0026#34; # === Sentry # NEXT_PUBLIC_SENTRY_DSN: \u0026#39;http://spotlight:8969/stream\u0026#39; # SENTRY_SPOTLIGHT: \u0026#39;1\u0026#39; # === Misc Settings OPENAI_API_KEY: \u0026#39;${OPENAI_API_KEY:-}\u0026#39; NEXT_PUBLIC_DISCORD_SUPPORT: \u0026#39;\u0026#39; NEXT_PUBLIC_POLOTNO: \u0026#39;\u0026#39; API_LIMIT: 30 # === Payment / Stripe Settings FEE_AMOUNT: 0.05 STRIPE_PUBLISHABLE_KEY: \u0026#39;${STRIPE_PUBLISHABLE_KEY:-}\u0026#39; STRIPE_SECRET_KEY: \u0026#39;${STRIPE_SECRET_KEY:-}\u0026#39; STRIPE_SIGNING_KEY: \u0026#39;${STRIPE_SIGNING_KEY:-}\u0026#39; STRIPE_SIGNING_KEY_CONNECT: \u0026#39;${STRIPE_SIGNING_KEY_CONNECT:-}\u0026#39; # === Developer Settings NX_ADD_PLUGINS: false # === Short Link Service Settings (Optional) # DUB_TOKEN: \u0026#34;${DUB_TOKEN}\u0026#34; # DUB_API_ENDPOINT: \u0026#34;https://api.dub.co\u0026#34; # DUB_SHORT_LINK_DOMAIN: \u0026#34;dub.sh\u0026#34; # SHORT_IO_SECRET_KEY: \u0026#34;${SHORT_IO_SECRET_KEY}\u0026#34; # KUTT_API_KEY: \u0026#34;${KUTT_API_KEY}\u0026#34; # KUTT_API_ENDPOINT: \u0026#34;https://kutt.it/api/v2\u0026#34; # KUTT_SHORT_LINK_DOMAIN: \u0026#34;kutt.it\u0026#34; # LINK_DRIP_API_KEY: \u0026#34;${LINK_DRIP_API_KEY}\u0026#34; # LINK_DRIP_API_ENDPOINT: \u0026#34;https://api.linkdrip.com/v1/\u0026#34; # LINK_DRIP_SHORT_LINK_DOMAIN: \u0026#34;dripl.ink\u0026#34; volumes: - ./data/postiz-config:/config/ - ./data/postiz-uploads:/uploads/ ports: - \u0026#34;4007:5000\u0026#34; # --- Traefik: enable if you decide to publish Postiz via the Docker provider --- # labels: # - \u0026#34;traefik.enable=true\u0026#34; # - \u0026#34;traefik.http.routers.postiz.rule=Host(`${POSTIZ_DOMAIN}`)\u0026#34; # - \u0026#34;traefik.http.routers.postiz.entrypoints=websecure\u0026#34; # - \u0026#34;traefik.http.routers.postiz.tls=true\u0026#34; # - \u0026#34;traefik.http.services.postiz.loadbalancer.server.port=5000\u0026#34; networks: - postiz-network - temporal-network healthcheck: test: [\u0026#34;CMD\u0026#34;, \u0026#34;node\u0026#34;, \u0026#34;-e\u0026#34;, \u0026#34;const r=require(\u0026#39;http\u0026#39;).get(\u0026#39;http://localhost:5000/\u0026#39;,res=\u0026gt;process.exit(res.statusCode\u0026lt;500?0:1));r.on(\u0026#39;error\u0026#39;,()=\u0026gt;process.exit(1));r.setTimeout(4000,()=\u0026gt;{r.destroy();process.exit(1)})\u0026#34;] interval: 30s timeout: 10s retries: 5 start_period: 120s depends_on: postiz-redis: condition: service_healthy temporal: condition: service_healthy # There\u0026#39;s no longer a dedicated Postgres container for Postiz - it uses # an external Postgres 16 at 192.x.x.x. # The POSTIZ_DB_* database and user must be created there in advance manually # (via pgAdmin); Postiz applies migrations itself on startup. postiz-redis: image: redis:7.2 container_name: postiz-redis restart: always healthcheck: test: [\u0026#34;CMD-SHELL\u0026#34;, \u0026#34;redis-cli ping | grep -q PONG\u0026#34;] interval: 10s timeout: 5s retries: 5 start_period: 5s volumes: - ./data/redis:/data networks: - postiz-network # App monitoring / debugging - enabled via docker compose --profile debug up spotlight: profiles: [debug] pull_policy: always container_name: spotlight restart: unless-stopped ports: - \u0026#34;127.0.0.1:8969:8969\u0026#34; image: ghcr.io/getsentry/spotlight:latest networks: - postiz-network # ----------------------- # Temporal Stack # ----------------------- temporal-elasticsearch: container_name: temporal-elasticsearch image: elasticsearch:7.17.27 restart: always environment: - cluster.routing.allocation.disk.threshold_enabled=true - cluster.routing.allocation.disk.watermark.low=512mb - cluster.routing.allocation.disk.watermark.high=256mb - cluster.routing.allocation.disk.watermark.flood_stage=128mb - discovery.type=single-node - ES_JAVA_OPTS=-Xms256m -Xmx256m - xpack.security.enabled=false networks: - temporal-network expose: - 9200 healthcheck: test: [\u0026#34;CMD-SHELL\u0026#34;, \u0026#34;curl -fsS \\\u0026#34;http://localhost:9200/_cluster/health?wait_for_status=yellow\u0026amp;timeout=5s\\\u0026#34; || exit 1\u0026#34;] interval: 10s timeout: 10s retries: 10 start_period: 60s volumes: - ./data/temporal-elasticsearch:/usr/share/elasticsearch/data temporal-postgresql: container_name: temporal-postgresql image: postgres:16 restart: always environment: POSTGRES_USER: \u0026#39;${TEMPORAL_DB_USER}\u0026#39; POSTGRES_PASSWORD: \u0026#39;${TEMPORAL_DB_PASSWORD}\u0026#39; networks: - temporal-network expose: - 5432 healthcheck: test: [\u0026#34;CMD-SHELL\u0026#34;, \u0026#34;pg_isready -U ${TEMPORAL_DB_USER}\u0026#34;] interval: 10s timeout: 5s retries: 5 start_period: 10s volumes: - ./data/temporal-postgres:/var/lib/postgresql/data temporal: container_name: temporal restart: always ports: - \u0026#34;127.0.0.1:7233:7233\u0026#34; image: temporalio/auto-setup:1.28.1 depends_on: temporal-postgresql: condition: service_healthy temporal-elasticsearch: condition: service_healthy environment: - DB=postgres12 - DB_PORT=5432 - POSTGRES_USER=${TEMPORAL_DB_USER} - POSTGRES_PWD=${TEMPORAL_DB_PASSWORD} - POSTGRES_SEEDS=temporal-postgresql - DYNAMIC_CONFIG_FILE_PATH=config/dynamicconfig/development-sql.yaml - ENABLE_ES=true - ES_SEEDS=temporal-elasticsearch - ES_VERSION=v7 - TEMPORAL_NAMESPACE=default networks: - temporal-network healthcheck: test: [\u0026#34;CMD\u0026#34;, \u0026#34;temporal\u0026#34;, \u0026#34;operator\u0026#34;, \u0026#34;cluster\u0026#34;, \u0026#34;health\u0026#34;, \u0026#34;--address\u0026#34;, \u0026#34;temporal:7233\u0026#34;] interval: 10s timeout: 5s retries: 10 start_period: 30s volumes: - ./dynamicconfig:/etc/temporal/config/dynamicconfig labels: kompose.volume.type: configMap temporal-admin-tools: container_name: temporal-admin-tools image: temporalio/admin-tools:1.28.1-tctl-1.18.4-cli-1.4.1 restart: on-failure environment: - TEMPORAL_ADDRESS=temporal:7233 - TEMPORAL_CLI_ADDRESS=temporal:7233 networks: - temporal-network stdin_open: true depends_on: temporal: condition: service_healthy tty: true temporal-ui: container_name: temporal-ui image: temporalio/ui:2.34.0 restart: always environment: - TEMPORAL_ADDRESS=temporal:7233 - TEMPORAL_CORS_ORIGINS=http://127.0.0.1:3000 networks: - temporal-network ports: - \u0026#34;127.0.0.1:8080:8080\u0026#34; healthcheck: test: [\u0026#34;CMD\u0026#34;, \u0026#34;curl\u0026#34;, \u0026#34;-f\u0026#34;, \u0026#34;http://localhost:8080/healthz\u0026#34;] interval: 30s timeout: 5s retries: 5 start_period: 20s depends_on: temporal: condition: service_healthy networks: postiz-network: external: false temporal-network: driver: bridge name: temporal-network .env file\n# Domain Postiz will respond on (without https://) POSTIZ_DOMAIN=postiz.domain.ru # Generate a random string, e.g.: openssl rand -hex 32 POSTIZ_JWT_SECRET=secret # Postiz database — external Postgres 16 (same server as Forgejo) # The database and user must be created on the server manually in advance (pgAdmin) POSTIZ_DB_HOST=x.x.x.x POSTIZ_DB_PORT=5432 POSTIZ_DB_USER=postiz POSTIZ_DB_PASSWORD=postiz POSTIZ_DB_NAME=postiz # Temporal database (separate from the Postiz database) TEMPORAL_DB_USER=temporal TEMPORAL_DB_PASSWORD=CHANGE_ME # Authentik SSO (authentik.secret.ru) — client_id/secret from the provider set up in Authentik # POSTIZ_OAUTH_CLIENT_ID=secret # POSTIZ_OAUTH_CLIENT_SECRET=secret # Below — fill in as you connect social networks/integrations, leave empty if unused X_API_KEY= X_API_SECRET= LINKEDIN_CLIENT_ID= LINKEDIN_CLIENT_SECRET= REDDIT_CLIENT_ID= REDDIT_CLIENT_SECRET= GITHUB_CLIENT_ID= GITHUB_CLIENT_SECRET= BEEHIIVE_API_KEY= BEEHIIVE_PUBLICATION_ID= THREADS_APP_ID= THREADS_APP_SECRET= FACEBOOK_APP_ID= FACEBOOK_APP_SECRET= YOUTUBE_CLIENT_ID=secret YOUTUBE_CLIENT_SECRET=secret TIKTOK_CLIENT_ID= TIKTOK_CLIENT_SECRET= PINTEREST_CLIENT_ID= PINTEREST_CLIENT_SECRET= DRIBBBLE_CLIENT_ID= DRIBBBLE_CLIENT_SECRET= DISCORD_CLIENT_ID= DISCORD_CLIENT_SECRET= DISCORD_BOT_TOKEN_ID= SLACK_ID= SLACK_SECRET= SLACK_SIGNING_SECRET= MASTODON_CLIENT_ID= MASTODON_CLIENT_SECRET= OPENAI_API_KEY= STRIPE_PUBLISHABLE_KEY= STRIPE_SECRET_KEY= STRIPE_SIGNING_KEY= STRIPE_SIGNING_KEY_CONNECT= DISABLE_REGISTRATION=true SSO via Authentik - and the DISABLE_REGISTRATION trap # I already have Authentik (authentik.stilicho.ru) set up, through which SSO is configured for almost the entire homelab, so naturally the first thing I did was go set it up for Postiz too. The integration itself is described in Postiz\u0026rsquo;s official OIDC documentation - you create an OAuth2/OpenID provider in Authentik, set six variables in Postiz (POSTIZ_GENERIC_OAUTH, POSTIZ_OAUTH_URL, POSTIZ_OAUTH_AUTH_URL, POSTIZ_OAUTH_TOKEN_URL, POSTIZ_OAUTH_USERINFO_URL, POSTIZ_OAUTH_CLIENT_ID/SECRET), and a button for your provider appears on the login page instead of the GitHub/Google buttons.\nThe first subtlety - Postiz\u0026rsquo;s redirect URI isn\u0026rsquo;t a separate /callback path as usual, but simply /settings. The second subtlety, of the familiar-pitfall variety but with a twist opposite of what you\u0026rsquo;d expect: POSTIZ_OAUTH_AUTH_URL and the neighboring variables for Authentik must end with a trailing slash. Starting with version 2023.10, Authentik removed the automatic redirect for paths without a trailing slash - previously /application/o/authorize without a slash would redirect itself to the right address, but now it just returns a 404. So you need .../authorize/, .../token/, .../userinfo/ - with the trailing slash, otherwise you\u0026rsquo;ll get a 404 error.\nBut there was a third, much less obvious trap, and the most annoying one at that. You spin up the app, create an admin account, then turn on DISABLE_REGISTRATION=true (so no one else can register on a publicly exposed instance, if yours is publicly exposed, of course) \u0026hellip; and after setting up Authentik for SSO, logging in through it just doesn\u0026rsquo;t work. It turned out the issue had nothing to do with the OIDC configuration - it\u0026rsquo;s a confirmed bug in Postiz itself: while DISABLE_REGISTRATION is enabled, OIDC login doesn\u0026rsquo;t work for anyone at all, and on top of that the container itself breaks. You can follow the discussion and status in issue #807 in the Postiz repository.\nKeeping registration permanently open just so login via Authentik works isn\u0026rsquo;t really an option - that\u0026rsquo;s exactly what I was trying to avoid in the first place. The working solution is to bypass Postiz\u0026rsquo;s built-in OIDC entirely and put authorization through Authentik at the Traefik level itself (forward auth), exactly the way I\u0026rsquo;ve already done for services without their own login, like Homepage or the arr stack. In that setup, nobody can reach Postiz at all without authenticating through Authentik, and DISABLE_REGISTRATION=true inside Postiz itself can be left as-is - it\u0026rsquo;s no longer your only line of defense there.\nThat was quite the problem - I spent over an hour debugging it, then gave up and went with the solution described above.\nConnecting YouTube # With YouTube, everything turned out to be surprisingly predictable. The Postiz provider is full-featured, with no real limitations. The only catch is that for a self-hosted instance you need to set up your own OAuth application in Google Cloud - nobody hands out ready-made keys for the self-hosted version, those only exist for the cloud version.\nGo to the Credentials page in Google Cloud, create a project (or use an existing one if you already have one for other purposes). In the \u0026ldquo;Enabled APIs and Services\u0026rdquo; section, enable three APIs at once - YouTube Data API v3, YouTube Analytics API, and YouTube Reporting API. Without the second and third, publishing will generally still work, but some features like analytics and reports simply won\u0026rsquo;t function - better to enable all three at once so you don\u0026rsquo;t later wonder why something isn\u0026rsquo;t showing up.\nIf you don\u0026rsquo;t have any Google Cloud project yet # A separate note for those who, like me, have never set up a Google Cloud project before. Since 2022, Google hasn\u0026rsquo;t been registering new Cloud users from Russia - at the country selection step, it\u0026rsquo;s simply not in the list. This can be worked around via \u0026ldquo;that certain technology\u0026rdquo; that exits through a country that is in the list (it\u0026rsquo;s important that the IP and the country specified at registration match, otherwise the chance of getting flagged for suspected fraud is higher than usual). The good news - you don\u0026rsquo;t need a billing account at all to get OAuth keys; YouTube Data API v3 works within the free quota, so the only hurdle is a one-time registration, not payment.\nTo avoid risking my main channel, I split things across different Google accounts: I set up the Cloud project on a separate \u0026ldquo;technical\u0026rdquo; address (via\u0026hellip;), while I authorized the channel itself in Postiz under the regular account it\u0026rsquo;s tied to. An OAuth application can authorize access to the data of any user who agrees to connect it - it doesn\u0026rsquo;t have to belong to the channel\u0026rsquo;s owner. The only nuance is that since the app stays in Testing status (there\u0026rsquo;s no reason to publish it), you need to explicitly add the channel\u0026rsquo;s address to Test users on the Audience tab in Google Auth Platform, otherwise Google will show \u0026ldquo;app hasn\u0026rsquo;t been verified\u0026rdquo; for that specific account when you try to authorize.\nBy the way (if you\u0026rsquo;ve seen the YouTube videos about this app), the interface for creating an OAuth app in Google Cloud has actually changed in 2026 - it used to be the \u0026ldquo;OAuth consent screen,\u0026rdquo; now it\u0026rsquo;s \u0026ldquo;Google Auth Platform\u0026rdquo; with a wizard consisting of App Information → Audience → Contact Information steps, and separate Branding/Audience/Data Access/Clients tabs after creation. The gist is the same, just don\u0026rsquo;t be alarmed if a screenshot from someone\u0026rsquo;s old guide doesn\u0026rsquo;t match what you\u0026rsquo;re seeing.\nNext, in Google Auth Platform, on the Clients tab - \u0026ldquo;Create Credentials\u0026rdquo; → \u0026ldquo;OAuth client ID.\u0026rdquo; Choose Web application as the app type, and in \u0026ldquo;Authorized redirect URIs\u0026rdquo; enter an address like:\nhttps://postiz.domain.ru/integrations/social/youtube (for local development without a domain, the docs reference http://localhost:5000/integrations/social/youtube, but with a real domain behind Traefik, we need the first version).\nEnter the resulting keys into the Postiz config:\nYOUTUBE_CLIENT_ID=\u0026#34;your-client-id\u0026#34; YOUTUBE_CLIENT_SECRET=\u0026#34;your-client-secret\u0026#34; Restart Postiz - and in the integrations section you can now just click \u0026ldquo;Connect YouTube,\u0026rdquo; the button is there, everything works through the usual OAuth popup as normal (don\u0026rsquo;t forget to select the channel account in the popup window, not the technical one you used to set up the Cloud project).\nThe one thing worth knowing in advance, rather than after a failed attempt to publish a post - YouTube in Postiz only accepts videos, and exactly one attachment per post. No image carousels and no posts without video - it simply won\u0026rsquo;t work. On the plus side, the available settings include title, privacy (public/unlisted/private), a \u0026ldquo;made for kids\u0026rdquo; flag, tags, and a custom thumbnail.\nAnd one more nuance - Postiz has no idea what\u0026rsquo;s already happening on the platform itself. Its calendar is built strictly from its own database: it only shows what was scheduled through Postiz itself, and it doesn\u0026rsquo;t pull in or sync anything you\u0026rsquo;ve already uploaded directly through YouTube Studio. It\u0026rsquo;s strictly a push tool, not a sync tool. If you start managing your schedule through Postiz, anything old that was published outside of it or before it simply won\u0026rsquo;t show up there.\nConnecting VK and RuTube # Well, we don\u0026rsquo;t connect anything. Let me spell it out. VK support is officially claimed, and it does exist. All you need, as everywhere else, is to get a Client Secret and a Client ID. Sounds simple, right? On top of that, you don\u0026rsquo;t even need to fake registering from another country. Yeah, right. You can only get the coveted credentials by registering with VK Business, because such credentials are only issued to those who\u0026rsquo;ve verified themselves as a developer. According to VK\u0026rsquo;s administration, of course.\nIt gets better from there: you need to provide your tax ID, then specify who you are - a sole proprietor or self-employed. And as the cherry on top, you have to verify your identity through SberID, T-Bank ID, or Gosuslugi. I gave up at the last step. Forgot to mention - you can only post to a community, not a personal page. RuTube, which has no official Postiz support at all, I didn\u0026rsquo;t even bother starting on.\nI\u0026rsquo;m not trying to mock our services, but I see a clear gap between the talk about wanting to attract content creators and the bureaucratic hell someone has to go through just to post pictures of cats.\nConclusion # Bottom line - YouTube connects in a standard, predictable way; the only real complexity is the Brand Account and the patience needed for Google\u0026rsquo;s settings to propagate. With VK, something might eventually have worked out, but to get there you\u0026rsquo;d have to go through a \u0026ldquo;job interview\u0026rdquo; complete with submitting documents, your family history, and a full account of your employment record. Like I\u0026rsquo;m applying for a government job or something?! And RuTube simply isn\u0026rsquo;t in Postiz at the moment - if having video specifically there matters to you, you\u0026rsquo;ll either have to publish it by hand, write your own provider, or look at a third-party service.\nIn the end I dropped the idea of using Postiz, because no real automation came out of it. I wanted to automate publishing to three services, and ended up with just one working - which you really can\u0026rsquo;t call automation by any stretch.\nI think being honest about what doesn\u0026rsquo;t work \u0026ldquo;out of the box\u0026rdquo; despite the promises is, in my view, more useful than drawing a nice diagram that falls apart at the first step in practice - and in this case, I couldn\u0026rsquo;t even manage the first step.\n","date":"August 16, 2026","externalUrl":null,"permalink":"/en/posts/postiz-youtube-vk-rutube/","section":"Posts","summary":"I set up self-hosted Postiz and try to connect it to YouTube, VK, and RuTube - walking through the real steps, the required env variables, and known bugs. In the end, out of three platforms, only one works reliably, and I honestly explain why.","title":"Postiz: trying to automate YouTube, VK, and RuTube - and why only one out of three actually works","type":"posts"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/posts/","section":"Posts","summary":"","title":"Posts","type":"posts"},{"content":"ProHomeLab is a blog and YouTube channel about homelab and self-hosting, covering how to build your own home infrastructure from the ground up. Here you\u0026rsquo;ll find step-by-step guides on virtualization, networking, containers, and security — from your first Proxmox server to setups like Traefik + Authentik.\nEvery article includes screenshots, working configurations, and videos from the @prohomelab YouTube channel, making it as easy to follow along as watching a video.\n","date":"August 16, 2026","externalUrl":null,"permalink":"/en/","section":"ProHomeLab — a blog about self-hosting and homelab","summary":"Practical articles and videos about homelab and self-hosting: Proxmox virtualization, containers, Traefik, Portainer, and everything you need to run your own services at home.","title":"ProHomeLab — a blog about self-hosting and homelab","type":"page"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/tags/rutube/","section":"Tags","summary":"","title":"RuTube","type":"tags"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/categories/self-hosting/","section":"Categories","summary":"","title":"Self-Hosting","type":"categories"},{"content":"A series of articles about Self-Hosting — running services and applications yourself on your own servers. We cover installing and configuring popular solutions: Nextcloud, Mealie, Linkwarden, Audiobookshelf, as well as tools for backup, proxying, and access management.\n","date":"August 16, 2026","externalUrl":null,"permalink":"/en/posts/selfhosting/","section":"Posts","summary":"A series of articles about Self-Hosting — running services and applications yourself on your own servers. We cover installing and configuring popular solutions like Nextcloud, Mealie, Linkwarden, and Audiobookshelf, as well as tools for backup, proxying, and access management.","title":"Self-Hosting","type":"posts"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/series/self-hosting/","section":"Series","summary":"","title":"Self-Hosting","type":"series"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/tags/self-hosting/","section":"Tags","summary":"","title":"Self-Hosting","type":"tags"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/series/","section":"Series","summary":"","title":"Series","type":"series"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/tags/","section":"Tags","summary":"","title":"Tags","type":"tags"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/tags/vk/","section":"Tags","summary":"","title":"VK","type":"tags"},{"content":"","date":"August 16, 2026","externalUrl":null,"permalink":"/en/tags/youtube/","section":"Tags","summary":"","title":"YouTube","type":"tags"},{"content":"","date":"August 11, 2026","externalUrl":null,"permalink":"/en/tags/docker/","section":"Tags","summary":"","title":"Docker","type":"tags"},{"content":"","date":"August 11, 2026","externalUrl":null,"permalink":"/en/categories/docker-ui/","section":"Categories","summary":"","title":"Docker UI","type":"categories"},{"content":"","date":"August 11, 2026","externalUrl":null,"permalink":"/en/tags/komodo/","section":"Tags","summary":"","title":"Komodo","type":"tags"},{"content":" Why Move from Portainer to Komodo # Portainer has long been the de facto standard for managing Docker through a web interface, but it has limitations:\nno full-fledged CI/CD workflow. It does have one, but not at the level competitors offer; weak git repository support. Again, you can connect Portainer to GitHub and it will even work, but not all the functionality is there, and what is there isn\u0026rsquo;t implemented the way competitors do it. an aging UI. Yes, I fully understand that interface design is a very subjective thing. Some like retro, some like Metro. But still, some things are confusing. some functionality is paid. Komodo is a younger project (source on GitHub) that closes these gaps: it can deploy stacks straight from git, supports distributed management of multiple hosts via the Periphery agent - and this is baked into its architecture from the start - and offers a more modern approach to CI/CD within a home infrastructure. As far as I can tell, these are exactly the things the developers focused on. The full list of features is in the official \u0026ldquo;What is Komodo\u0026rdquo; description.\nIn this article I\u0026rsquo;ll describe the full installation: from the docker-compose file to setting up SSO via Authentik and connecting an additional host as a remote agent.\nArchitecture # Komodo consists of three components:\nCore - the central service, web interface, and API. Periphery - an agent that runs on each managed host and talks to Core. This component is required for installation even on the main host. Database - Core stores all data (resource configurations, users, logs) in a MongoDB-compatible database. The database deserves a separate mention: Komodo can work either with a regular MongoDB, or with FerretDB - a proxy adapter that emulates the MongoDB protocol while actually storing data in Postgres. No other option is currently supported. For myself, and while writing this article, I chose the classic MongoDB option - it\u0026rsquo;s officially recommended and the most tested (details in the Core setup documentation). Although why they didn\u0026rsquo;t provide the option to work with Postgres directly is not really clear! From my point of view, that\u0026rsquo;s a huge downside.\nPreparation: Directory Structure # I prefer bind mounts over named Docker volumes - it\u0026rsquo;s more convenient for me to make backups and work with data directly from the host. But this adds certain complications, especially around directory permissions. My project data lives at /home/stilicho/docker/komodo.\nLet\u0026rsquo;s create the directory structure in advance:\nmkdir -p /home/stilicho/docker/komodo/{mongo/data,mongo/configdb,keys,backups} As you can tell, I already looked at the project structure ahead of time and tested everything, so the command above wasn\u0026rsquo;t pulled out of thin air.\nNote Something worth thinking through right away, not later. If, like me, all your other docker-compose projects live next to each other in a common parent folder (for example /home/stilicho/docker/vaultwarden, /home/stilicho/docker/gotify, etc.), then PERIPHERY_ROOT_DIRECTORY needs to point to that parent directory (/home/stilicho/docker), not to a subfolder inside komodo. Otherwise, later, when you migrate existing stacks into Komodo (there\u0026rsquo;s a section on this below), Periphery physically won\u0026rsquo;t be able to see their files and will throw No such file or directory, even if the path in the UI is set correctly. More details in the section about migrating stacks. I know what I\u0026rsquo;m talking about, since I ran into this problem myself.\nInstallation Configuration # docker-compose.yaml # Below is the resulting compose file. It\u0026rsquo;s based on the official MongoDB example, with a few important tweaks:\nvolumes replaced with bind mounts under our path; each service given a container_name for convenience; ################################ # 🦎 KOMODO COMPOSE - MONGO 🦎 ################################ # This Docker Compose file deploys three Komodo components: # 1. MongoDB - Komodo\u0026#39;s database. # 2. Komodo Core - Komodo\u0026#39;s main server and web interface. # 3. Komodo Periphery - the agent that performs Docker # operations on the managed server. services: # ============================================================ # MongoDB # ============================================================ mongo: # MongoDB Docker image. # Without a tag specified, the latest tag will be used. image: mongo # Fixed container name. # This makes the container named komodo-mongo, # regardless of the name of the Compose project directory. container_name: komodo-mongo labels: # Empty label that tells Komodo itself # that this container should not be stopped when performing # the StopAllContainers operation. # # This is especially important because MongoDB is # Komodo\u0026#39;s own database. komodo.skip: # Additional MongoDB startup parameters. # # --quiet disables some of MongoDB\u0026#39;s informational messages. # # --wiredTigerCacheSizeGB 0.25 limits the WiredTiger cache size # to about 256 MB. # # For a small home server this keeps MongoDB # from hogging extra RAM. command: --quiet --wiredTigerCacheSizeGB 0.25 # Automatically restarts the container after a crash, # as well as after the Docker host reboots. # # If the container was stopped manually, Docker will not # automatically start it again. restart: unless-stopped # Publishing MongoDB\u0026#39;s port externally is disabled. # # MongoDB doesn\u0026#39;t need to be reachable from the host: # Komodo Core connects to it directly # via the internal Docker network komodo. # # ports: # - 27017:27017 volumes: # Persistent storage for MongoDB data. # # Left side - directory on the Docker host. # Right side - directory inside the MongoDB container. # # This makes the database data persist across container recreation. - /home/stilicho/docker/komodo/mongo/data:/data/db # Persistent storage for MongoDB configuration data. - /home/stilicho/docker/komodo/mongo/configdb:/data/configdb networks: # Connect MongoDB to Komodo\u0026#39;s internal network. # # On this network, Komodo Core can reach MongoDB # by the service name \u0026#34;mongo\u0026#34; and port 27017. - komodo environment: # MongoDB admin username. # # The value comes from the KOMODO_DATABASE_USERNAME variable, # defined in the Compose environment. MONGO_INITDB_ROOT_USERNAME: ${KOMODO_DATABASE_USERNAME} # MongoDB admin password. # # The value comes from the KOMODO_DATABASE_PASSWORD variable. MONGO_INITDB_ROOT_PASSWORD: ${KOMODO_DATABASE_PASSWORD} # ============================================================ # Komodo Core # ============================================================ core: # Komodo Core Docker image. # # The COMPOSE_KOMODO_IMAGE_TAG variable lets you choose # the image version. # # If the variable is not set, tag \u0026#34;2\u0026#34; is used. image: ghcr.io/moghtech/komodo-core:${COMPOSE_KOMODO_IMAGE_TAG:-2} # Fixed name for the Komodo Core container. container_name: komodo-core # Runs an init process inside the container. # # This helps correctly handle signals and processes # inside the container. init: true # Automatically restarts the container after a crash # or Docker host reboot. restart: unless-stopped depends_on: # Komodo Core depends on MongoDB. # # Compose will first start the mongo container, # then the core container. # # Important: depends_on doesn\u0026#39;t guarantee that MongoDB is fully # ready to accept connections - it only controls startup order. - mongo ports: # Publishes port 9120 of the Komodo Core container # to port 9120 on the Docker host. # # In this Compose file, this allows accessing Core directly, # bypassing Traefik. # # If access to Komodo should only go through Traefik, # this port publication can be removed later. - 9120:9120 # Loads environment variables from the compose.env file. # # This lets you avoid storing secrets directly # in docker-compose.yml. env_file: ./compose.env environment: # MongoDB address for Komodo Core. # # \u0026#34;mongo\u0026#34; - the MongoDB service\u0026#39;s DNS name inside the Docker network. # 27017 - MongoDB\u0026#39;s standard port. # # So Core reaches the DB as: # mongo:27017 KOMODO_DATABASE_ADDRESS: mongo:27017 volumes: # Keys used for communication between Komodo Core # and Komodo Periphery. # # Host directory: # /home/stilicho/docker/komodo/keys # # Directory inside the container: # /config/keys - /home/stilicho/docker/komodo/keys:/config/keys # Directory for Komodo database backups. # # Backups are saved on the Docker host and therefore # won\u0026#39;t disappear when the Core container is recreated. # # Komodo documentation: # https://komo.do/docs/setup/backup - /home/stilicho/docker/komodo/backups:/backups networks: # Connection to the proxy network. # # This network is used by Traefik to reach # the Komodo Core container. - proxy # Connection to Komodo\u0026#39;s internal network. # # Through this, Core communicates with MongoDB # and other Komodo components. - komodo security_opt: # Prevents the container from gaining new privileges. # # This is an additional security measure. # It prevents privilege escalation of a process inside the container. - no-new-privileges:true labels: # ======================================================== # Traefik # ======================================================== # Allow Traefik to discover and serve this container. - \u0026#34;traefik.enable=true\u0026#34; # -------------------------------------------------------- # HTTP router # -------------------------------------------------------- # Komodo\u0026#39;s HTTP router works via the web entrypoint, # usually corresponding to port 80. - \u0026#34;traefik.http.routers.komodo.entrypoints=web\u0026#34; # The router triggers if the request\u0026#39;s Host header # equals komodo.stilicho.ru. - \u0026#34;traefik.http.routers.komodo.rule=Host(`komodo.stilicho.ru`)\u0026#34; # Creates a middleware that redirects HTTP requests # to HTTPS. - \u0026#34;traefik.http.middlewares.komodo-https-redirect.redirectscheme.scheme=https\u0026#34; # Attaches the redirect middleware to the HTTP router. - \u0026#34;traefik.http.routers.komodo.middlewares=komodo-https-redirect\u0026#34; # -------------------------------------------------------- # HTTPS router # -------------------------------------------------------- # The HTTPS router uses the websecure entrypoint, # usually corresponding to port 443. - \u0026#34;traefik.http.routers.komodo-secure.entrypoints=websecure\u0026#34; # The HTTPS router also only serves requests # for the domain komodo.stilicho.ru. - \u0026#34;traefik.http.routers.komodo-secure.rule=Host(`komodo.stilicho.ru`)\u0026#34; # Enable TLS for this router. - \u0026#34;traefik.http.routers.komodo-secure.tls=true\u0026#34; # Explicitly specify that the HTTPS router should use # the Traefik service named komodo. - \u0026#34;traefik.http.routers.komodo-secure.service=komodo\u0026#34; # Tell Traefik that inside the Docker network # the Komodo Core app listens on port 9120. # # Traefik talks to the container directly, # so publishing port 9120 on the host isn\u0026#39;t required for it. - \u0026#34;traefik.http.services.komodo.loadbalancer.server.port=9120\u0026#34; # Tell Traefik which Docker network to use # to connect to the container. # # The proxy network is used here. - \u0026#34;traefik.docker.network=proxy\u0026#34; # ============================================================ # Komodo Periphery # ============================================================ # Periphery can be run in two ways: # # 1. As a Docker container - this is the variant shown below. # # 2. As a systemd service directly on the host # using the Periphery binary. # # The containerized variant is convenient when Docker is already # the primary environment for managing services. periphery: # Komodo Periphery Docker image. # # Uses the same version variable as Core. # If the variable is not set, tag \u0026#34;2\u0026#34; is used. image: ghcr.io/moghtech/komodo-periphery:${COMPOSE_KOMODO_IMAGE_TAG:-2} # Fixed name for the Periphery container. container_name: komodo-periphery # Adds an init process inside the container. init: true # Automatically restarts Periphery after a crash # or Docker host reboot. restart: unless-stopped depends_on: # Periphery depends on Komodo Core. # # Compose starts Core first, # then Periphery. - core # Loads environment variables from compose.env. env_file: ./compose.env volumes: # Shared keys for Core and Periphery. # # This directory is used for authenticated # communication between Komodo components. - /home/stilicho/docker/komodo/keys:/config/keys # Docker socket. # # Through this socket, Periphery gets the ability # to manage the Docker daemon on the host: # # - create containers; # - stop containers; # - start containers; # - get information about containers; # - manage Docker Compose. # # IMPORTANT: # access to docker.sock effectively grants the container # a very high level of access to the Docker host. - /var/run/docker.sock:/var/run/docker.sock # Mount the host\u0026#39;s /proc inside the container. # # This lets Periphery get information # about processes and the host\u0026#39;s system state. - /proc:/proc # Periphery\u0026#39;s root directory. # # The PERIPHERY_ROOT_DIRECTORY variable determines # which directory Periphery will use # for storing working data. # # If the variable is not set, /etc/komodo is used. # # For example: # # PERIPHERY_ROOT_DIRECTORY=/etc/komodo # # then you get: # # /etc/komodo:/etc/komodo - ${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo}:${PERIPHERY_ROOT_DIRECTORY:-/etc/komodo} networks: # The proxy network connects Periphery to the shared Docker network # with Traefik and other services. - proxy # Komodo\u0026#39;s internal network for communication # between Komodo components. - komodo # ================================================================ # Docker networks # ================================================================ networks: # -------------------------------------------------------------- # proxy network # -------------------------------------------------------------- proxy: # This is an external Docker network. # # external: true means Compose does NOT create this network. # It must already exist. # # Usually such a network is created once: # # docker network create proxy # # After that, various Compose projects can connect to it, # such as Traefik, Komodo, and other services. external: true # -------------------------------------------------------------- # komodo network # -------------------------------------------------------------- komodo: # External Docker network for Komodo\u0026#39;s internal components. # # It is used for communication between: # # Komodo Core # │ # ├── MongoDB # │ # └── Periphery # # Like proxy, this network must be created beforehand. external: true flowchart LR Internet[\"Internet / LAN\"] Traefik[\"Traefik\"] Core[\"Komodo Core\n:9120\"] Mongo[\"MongoDB\n:27017\"] Periphery[\"Komodo Periphery\"] Host[\"Docker Host\"] Internet --\u003e|HTTPS| Traefik subgraph Networks[\"Docker Networks\"] direction LR subgraph Proxy[\"proxy\"] Traefik end subgraph Komodo[\"komodo\"] Core Mongo Periphery end Traefik --\u003e Core Core --\u003e Mongo Core --\u003e Periphery end Periphery --\u003e|docker.sock| Host So Traefik sees Core through proxy, while Core, MongoDB, and Periphery communicate through komodo.\nBoth networks are external, so create them ahead of time (Compose won\u0026rsquo;t create external networks itself):\ndocker network create proxy # if not already created for the reverse proxy docker network create komodo Caution An important point about networks. If you explicitly specify networks: for a service (as with core - the proxy network for Traefik), Docker Compose stops automatically adding it to the project\u0026rsquo;s default network. That\u0026rsquo;s why all three services that need to talk to each other (mongo, core, periphery) are explicitly connected to the separate komodo network - it\u0026rsquo;s specifically dedicated to internal communication between Komodo containers, while proxy is only used where the service actually needs to be visible to Traefik (i.e., only for core).\ncompose.env - environment variables # The second file, compose.env, stores all the settings and secrets. It\u0026rsquo;s mandatory and provided for by the developers from the start. Some values need to be generated yourself.\n#################################### # 🦎 KOMODO COMPOSE - VARIABLES 🦎 # #################################### COMPOSE_KOMODO_IMAGE_TAG=\u0026#34;2\u0026#34; COMPOSE_KOMODO_BACKUPS_PATH=/home/stilicho/docker/komodo/backups ## Database access credentials - be sure to change from defaults! KOMODO_DATABASE_USERNAME=\u0026lt;pick_a_username\u0026gt; KOMODO_DATABASE_PASSWORD=\u0026lt;pick_a_strong_password\u0026gt; TZ=Europe/Moscow #=-------------------------=# #= Komodo Core Environment =# #=-------------------------=# KOMODO_HOST=https://komodo.stilicho.ru KOMODO_TITLE=Komodo KOMODO_PERIPHERY_PUBLIC_KEY=file:/config/keys/periphery.pub ## Local admin in case of OIDC issues KOMODO_LOCAL_AUTH=true KOMODO_INIT_ADMIN_USERNAME=admin KOMODO_INIT_ADMIN_PASSWORD=\u0026lt;strong_password\u0026gt; KOMODO_FIRST_SERVER_NAME=Local KOMODO_DEFAULT_PAGINATION_LIMIT=50 ## Secrets - generate random strings, e.g.: openssl rand -hex 32 KOMODO_WEBHOOK_SECRET=\u0026lt;random_hex_32\u0026gt; KOMODO_JWT_SECRET=\u0026lt;random_hex_32\u0026gt; KOMODO_JWT_TTL=\u0026#34;1-day\u0026#34; KOMODO_MONITORING_INTERVAL=\u0026#34;15-sec\u0026#34; KOMODO_RESOURCE_POLL_INTERVAL=\u0026#34;1-hr\u0026#34; ## Enable this so OIDC users don\u0026#39;t require manual activation KOMODO_ENABLE_NEW_USERS=true ## OIDC Login (Authentik) KOMODO_OIDC_ENABLED=true KOMODO_OIDC_PROVIDER=https://authentik.stilicho.ru/application/o/komodo/ ## Uncomment only if Core reaches Authentik via an internal address ## different from the public domain above # KOMODO_OIDC_REDIRECT_HOST=https://auth.stilicho.ru KOMODO_OIDC_CLIENT_ID=\u0026lt;client_id_from_Authentik\u0026gt; KOMODO_OIDC_CLIENT_SECRET=\u0026lt;client_secret_from_Authentik\u0026gt; KOMODO_OIDC_AUTO_REDIRECT=false ## if set to true, there will be no login-choice option. Leave false until an admin has been created #=------------------------------=# #= Komodo Periphery Environment =# #=------------------------------=# PERIPHERY_CORE_ADDRESS=ws://core:9120 PERIPHERY_CONNECT_AS=${KOMODO_FIRST_SERVER_NAME} PERIPHERY_CORE_PUBLIC_KEYS=file:/config/keys/core.pub ## All Periphery stacks/repos/builds must live inside this path. ## Point this to the parent folder containing ALL your compose ## projects (including komodo, but also everything else) - otherwise ## Periphery won\u0026#39;t be able to read the files of existing stacks ## when you migrate them into Komodo. PERIPHERY_ROOT_DIRECTORY=/home/stilicho/docker PERIPHERY_INCLUDE_DISK_MOUNTS=/etc/hostname For the full list of variables with comments, see the original file on GitHub - there are a lot of them, I only kept what\u0026rsquo;s actually needed for a working installation. You can always add more to taste later, as needed.\nSetting Up Login via Authentik # If you, like me, use Authentik as a single sign-on point for homelab services, Komodo integrates with it nicely - there\u0026rsquo;s even a dedicated page about Authentik integration in the official documentation.\nConfiguring Authentik for Komodo # To authenticate Komodo users through Authentik, you need to create an Application + OAuth2/OpenID Connect Provider pair in Authentik, then pass the resulting parameters into Komodo\u0026rsquo;s configuration.\nImportant for Authentik 2026.5 and newer: this version added the ability to specify the Redirect URI type separately. For Komodo you need to add a Redirect URI of type Authorization.\nIn Authentik versions before 2026.5, all Redirect URIs were automatically treated as Authorization-type URIs. In that case it\u0026rsquo;s enough to add just the Authorization URL and not configure a Post Logout URI.\n1. Creating the Application and Provider in Authentik # Log in to Authentik as an administrator. Open the Authentik admin interface and go to:\nApplications → Applications\nClick New Application.\nAuthentik lets you create a pair right away:\nApplication OAuth2/OpenID Connect Provider Application # In the Name field, enter a clear application name:\nKomodo If needed, you can select an application group and configure display settings. Pay attention to the Slug field.\nFor example:\nkomodo You\u0026rsquo;ll need this slug when configuring Komodo. It\u0026rsquo;s actually been auto-generated in Authentik since around 2023 or so, I\u0026rsquo;m not sure why guides make a point of mentioning it.\n2. Creating the OAuth2/OpenID Connect Provider # In the Choose a Provider type section, select:\nOAuth2/OpenID Connect Then configure the Provider.\nName # You can enter:\nKomodo OIDC or leave the name Authentik suggests automatically.\nAuthorization flow # Choose an appropriate Authorization Flow.\nIf you already use a standard flow for OIDC applications, you can use it here.\nClient ID # Authentik will automatically create a:\nClient ID Save this value - you\u0026rsquo;ll need it in Komodo\u0026rsquo;s configuration.\nClient Secret # Also save the:\nClient Secret This is the secret Komodo will use when communicating with Authentik.\nImportant: the Client Secret must not be published or placed in a public Git repository.\n3. Configuring the Redirect URI # This is one of the most important integration parameters. In the Provider settings, find Redirect URIs.\nFor Komodo, add:\nhttps://komodo.stilicho.ru/auth/oidc/callback For Authentik 2026.5 and newer, set:\nType: Strict Mode: Authorization The resulting entry should look roughly like this:\nStrict | Authorization | https://komodo.stilicho.ru/auth/oidc/callback Why This Specific Address? # After successful authorization, Authentik needs to send the user back to Komodo.\nKomodo accepts the OIDC authentication result via:\n/auth/oidc/callback So the full URL is formed from Komodo\u0026rsquo;s address:\nhttps://komodo.stilicho.ru and the callback:\n/auth/oidc/callback Resulting in:\nhttps://komodo.stilicho.ru/auth/oidc/callback Important: the URL must exactly match the address Komodo actually uses. For example, you can\u0026rsquo;t specify http:// if Komodo is only reachable via https://.\n4. Signing Key # In the Signing Key field, choose any available signing key. If Authentik already has a default key, you can use it.\n5. Bindings - optional # The Configure Bindings section lets you restrict access to the application. For example, you can create a binding that only allows a specific user group to use Komodo. If you don\u0026rsquo;t need a restriction at this stage, you can skip this step.\n6. Launch URL - optional # For the Launch URL you can specify:\nhttps://komodo.stilicho.ru/auth/oidc/login This lets you launch Komodo\u0026rsquo;s authorization directly from Authentik\u0026rsquo;s Application Dashboard.\n7. Saving the Application # Once you\u0026rsquo;ve finished configuring, click:\nSubmit\nAuthentik now has the following set up:\nApplication │ └── OAuth2/OpenID Connect Provider │ ├── Client ID ├── Client Secret ├── Redirect URI └── Signing Key Save the following values:\nApplication Slug Client ID Client Secret You\u0026rsquo;ll need them when configuring Komodo.\nConfiguring Authentik in Komodo\u0026rsquo;s Environment File # Now you need to pass Komodo the connection parameters for Authentik. In this case, the parameters go in:\ncompose.env This file is loaded into the Komodo Core container via:\nenv_file: ./compose.env Add or change the following variables:\nKOMODO_HOST=https://komodo.stilicho.ru KOMODO_OIDC_ENABLED=true KOMODO_OIDC_PROVIDER=https://Authentik.stilicho.ru/application/o/\u0026lt;application_slug\u0026gt;/ KOMODO_OIDC_CLIENT_ID=\u0026lt;client_id_from_Authentik\u0026gt; KOMODO_OIDC_CLIENT_SECRET=\u0026lt;client_secret_from_Authentik\u0026gt; For example:\nKOMODO_HOST=https://komodo.stilicho.ru KOMODO_OIDC_ENABLED=true KOMODO_OIDC_PROVIDER=https://Authentik.stilicho.ru/application/o/komodo/ KOMODO_OIDC_CLIENT_ID=xxxxxxxxxxxxxxxxxxxxxxxx KOMODO_OIDC_CLIENT_SECRET=xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx Important point: Komodo can\u0026rsquo;t create OIDC users directly with admin rights. The first login always happens through the local admin defined in KOMODO_INIT_ADMIN_USERNAME/PASSWORD.\nLaunching # Before spinning up the containers, there\u0026rsquo;s one trick worth doing - a symlink, so Docker Compose automatically picks up the variables without the --env-file flag:\ncd /home/stilicho/docker/komodo ln -s compose.env .env docker compose up -d If you don\u0026rsquo;t create the symlink and run docker compose up -d without --env-file compose.env, Compose won\u0026rsquo;t substitute the\nKOMODO_DATABASE_USERNAME/PASSWORD variables into the environment: block of the mongo service - you\u0026rsquo;ll see a warning about empty values, and MongoDB will initialize with empty credentials. If this has already happened, you need to wipe the data and restart:\ndocker compose down rm -rf mongo/data/* mongo/configdb/* docker compose up -d Check the logs for errors:\ndocker logs komodo-mongo --tail 50 docker logs komodo-core --tail 50 First Login and Activating the OIDC Account # Open https://komodo.stilicho.ru. Log in as the local admin (admin / the password from compose.env). Click the OIDC button and log in via Authentik - Komodo will automatically create your user (already active, thanks to KOMODO_ENABLE_NEW_USERS=true). Go back in as the local admin → Settings → Users → find the newly created OIDC user → promote them to Admin. After that you can use Authentik login as your main method, with the local admin remaining as a fallback.\nWarning An important nuance with KOMODO_OIDC_AUTO_REDIRECT=true. This option automatically redirects any unauthenticated user to Authentik, bypassing Komodo\u0026rsquo;s login form - even in incognito mode. Because of this, you won\u0026rsquo;t be able to log in as the local admin the normal way. If you need to reach the local login form (for example, to promote a newly created OIDC user to admin), temporarily disable the redirect:\n# in compose.env KOMODO_OIDC_AUTO_REDIRECT=false docker compose up -d Log in as admin, make the necessary changes, then set KOMODO_OIDC_AUTO_REDIRECT=true back and apply docker compose up -d again.\nKomodo\u0026rsquo;s Features and Where to Find Things # Before moving on to configuration, let\u0026rsquo;s briefly go over the interface - what Komodo can actually do and where to find it after your first login. In the left-hand menu there are several main resource sections:\nServers - a list of connected Docker hosts (you\u0026rsquo;ll have at least one - the local one - plus any hosts connected via Periphery, like in the Immich section below). You can see connection status, CPU/RAM/disk, and Docker version here. Stacks - the equivalent of Portainer\u0026rsquo;s \u0026ldquo;Stacks\u0026rdquo;: management of docker-compose projects. This is where your stacks end up after migration (see the next section). Containers - a flat list of all containers across all connected servers, with start/stop/restart/logs/exec actions, not tied to a specific stack. Builds - if you want Komodo to build Docker images from a git repository itself (the CI part, which Portainer doesn\u0026rsquo;t have at all). Repos - management of git repositories that Komodo clones and can watch for changes (for auto-redeploy via webhook). Procedures and Actions - multi-step automation scenarios (e.g., \u0026ldquo;stop stack A → make a backup → update the image → start it again\u0026rdquo;), which can be triggered manually, on a schedule, or via webhook. Syncs - declarative configuration sync: you describe all resources (stacks, servers, procedures) in TOML files in git, and Komodo brings the real state in line with what\u0026rsquo;s described - similar to Terraform, but for your homelab. Alerts - the alert log. Settings - users, roles, API keys, webhooks for notifications (Discord/Slack/Telegram/Gotify, etc.). In a typical homelab scenario, you\u0026rsquo;ll spend 80% of your time in Servers and Stacks - the rest gets used as your needs grow (git builds, config sync).\nMigrating Existing docker-compose Stacks into Komodo # An important point to understand right away: unlike Dockge, Komodo does not scan the host automatically and does not pick up already-running compose projects on its own. Each stack needs to be explicitly \u0026ldquo;declared\u0026rdquo; in Komodo - specifying where its files are and which server it belongs to (the mechanics are described in the official Docker Compose / Stacks documentation). There\u0026rsquo;s no ready-made tool for automatic migration specifically from Portainer - the developers themselves confirm this in a GitHub discussion - you have to migrate manually, stack by stack (there\u0026rsquo;s an unofficial utility, komodo-import, which generates configuration from existing folders, but it\u0026rsquo;s a community tool, not part of Komodo itself). So I did it all by hand.\nThe good news: migration doesn\u0026rsquo;t require stopping your current containers. Portainer and Komodo work fine in parallel while you migrate stacks one at a time - your workflow isn\u0026rsquo;t interrupted.\nHow to Migrate One Stack # Servers → select a host (or the general Stacks section → Create Stack).\nGive the stack a name - it must match the name of the existing compose project. You can find out the current project name like this:\ndocker compose ls File source - choose one of three modes:\nUI Defined - paste the compose file contents directly into the web interface; Komodo writes the file to the host itself on deploy. Files on Server - specify the path to an already-existing compose file on the host (this is what you need for migrating existing stacks - just point it to where they already live, e.g. /home/alaricus/docker/vaultwarden). Git Repo - Komodo clones the repository to the host and deploys from there; changes are tracked in git, and you can set up auto-redeploy on push via webhook. For the Files on Server option - be sure to specify the correct Run Directory (the folder containing the compose file) and File Paths (the file name, usually docker-compose.yaml, docker-compose.yml, or compose.yaml).\nIf the stack has its own .env file (a common case - for example, I had many containers set up this way) - don\u0026rsquo;t try to recreate it via the Environment field in the UI. Use the separate Additional Env Files field, point it to .env (path relative to Run Directory), and make sure to uncheck \u0026ldquo;Track\u0026rdquo; - that\u0026rsquo;s specifically meant for externally managed files that you\u0026rsquo;ll keep editing manually on disk rather than through Komodo.\nAttach the stack to the desired Server (for the local host - the one named Local, etc.).\nClick Deploy (or first Refresh, so Komodo reads the current state without recreating the containers) - if containers are already running under the same project name, Komodo will simply \u0026ldquo;take them under management\u0026rdquo; rather than recreate them from scratch.\nImportant note about paths with remote hosts. If a stack is being migrated to a host with a Periphery agent, the path to the compose file must be reachable inside that agent\u0026rsquo;s root_directory. This applies to both installation methods, not just the container - I myself mistakenly thought the systemd variant didn\u0026rsquo;t have this restriction, but that\u0026rsquo;s not the case: root_directory is a built-in limitation of Periphery itself, not a consequence of Docker mounting. For the container, this means the path must fall inside the mounted PERIPHERY_ROOT_DIRECTORY; for systemd, it must match the root_directory in periphery.config.toml. In both cases, all your stacks must physically live inside that path.\nIf You Get \u0026ldquo;No Such File or Directory\u0026rdquo; # This is the most common error during the first stack migration, and it almost always means one thing: the containerized Periphery can\u0026rsquo;t physically see the specified directory, because PERIPHERY_ROOT_DIRECTORY points to too narrow a folder (for example, only to komodo itself, rather than to the parent directory containing all your projects - see the warning at the beginning of the article).\nStep-by-step diagnostics:\n1. Check that Periphery can actually see the stack\u0026rsquo;s directory:\ndocker exec komodo-periphery ls /home/stilicho/docker/\u0026lt;stack_name\u0026gt; If you get No such file or directory - the mount is too narrow; move on to step 2.\n2. Check that the .env → compose.env symlink was created (without it, PERIPHERY_ROOT_DIRECTORY from compose.env won\u0026rsquo;t be substituted into docker-compose.yaml when the container is recreated):\nls -la ~/docker/komodo/.env No file - create it (see the \u0026ldquo;Launching\u0026rdquo; section above).\n3. Fix PERIPHERY_ROOT_DIRECTORY in compose.env to point to the parent folder containing all your stacks, and recreate the containers from the project folder itself:\ncd /home/stilicho/docker/komodo docker compose down docker compose up -d Important: down + up, not restart.\n4. Check the actual mount inside the already-running container:\ndocker inspect komodo-periphery --format \u0026#39;{{range .Mounts}}{{.Source}} -\u0026gt; {{.Destination}}{{\u0026#34;\\n\u0026#34;}}{{end}}\u0026#39; You should see a line with your new parent directory, not the old narrow path.\n5. Go back to the stack page in the Komodo UI and click Refresh again (sometimes the interface holds a cached result from the previous attempt - if the error doesn\u0026rsquo;t disappear right away, refresh the whole browser page).\nBulk Migration via Sync # If you have a lot of stacks and migrating them one by one through the UI is tedious, you can describe them all at once declaratively via Syncs - TOML files with resource definitions that Komodo applies in one go. Details in the official Sync Resources documentation. For a homelab with a dozen or two containers, manual migration through the UI is usually faster than figuring out TOML syntax - but if you have fifty stacks, Sync is worth it. Thankfully I don\u0026rsquo;t have more than 50 on a single host yet.\nA single Komodo Core can manage several Docker hosts at once - for this, you need to install the Periphery agent on each additional host. For example, I have a separate host running Immich in Docker, which I connected exactly this way.\nPeriphery can be run as a Docker container (this is already built into our docker-compose.yaml for the local host), but for remote hosts, the officially recommended approach is a systemd install - it\u0026rsquo;s simpler and avoids complications with mounting the socket and paths through the container layer. A full description of all installation methods is in the official \u0026ldquo;Connect More Servers\u0026rdquo; documentation.\nRoot Installation (Recommended Method) # On the target host where you want to install the agent:\ncurl -sSL https://raw.githubusercontent.com/moghtech/komodo/main/scripts/setup-periphery.py \\ | sudo python3 - \\ --core-address=\u0026#34;https://komodo.stilicho.ru\u0026#34; \\ --connect-as=\u0026#34;immich-host\u0026#34; \\ --onboarding-key=\u0026#34;O-your_key_from_UI\u0026#34; The --onboarding-key comes from the Komodo UI: Servers → Add Server, where a one-time key of the form O-... is generated, which links the new agent to your Core.\nEnable autostart:\nsudo systemctl enable periphery sudo systemctl status periphery User Installation (Without a Root Service) # If you don\u0026rsquo;t want a root service, you can install Periphery as a user-level systemd service:\ncurl -sSL https://raw.githubusercontent.com/moghtech/komodo/main/scripts/setup-periphery.py \\ | python3 - --user \\ --core-address=\u0026#34;https://komodo.stilicho.ru\u0026#34; \\ --connect-as=\u0026#34;immich-host\u0026#34; \\ --onboarding-key=\u0026#34;O-your_key_from_UI\u0026#34; Be sure to enable linger, otherwise the service will stop when you log out of the SSH session:\nsudo loginctl enable-linger $USER Pitfalls I Hit (and How to Avoid Them from the Start) # With the user installation, at the time of writing this article the script does not change root_directory in the config - it remains /etc/komodo by default, which a regular user can\u0026rsquo;t write to. As a result, the service crashes with an error:\nFailed to write private key pem to \u0026#34;/etc/komodo/keys/periphery.key\u0026#34; Caused by: Permission denied (os error 13) And a second pitfall I hit later, when trying to migrate an existing immich stack into Komodo: root_directory isn\u0026rsquo;t just \u0026ldquo;where to put the keys\u0026rdquo; - it\u0026rsquo;s the only directory inside which Periphery can see any files at all (and this applies to the systemd variant too, not just the container - I myself mistakenly thought otherwise). If you point it to a \u0026ldquo;narrow\u0026rdquo; path like ~/.local/share/komodo, Periphery won\u0026rsquo;t see your actual compose projects living somewhere else (e.g., ~/docker/immich), and when you try to add a Stack you\u0026rsquo;ll get No such file or directory.\nTo avoid hitting these pitfalls twice, set the correct value in the config right away - the parent directory where all your compose projects on this host live (or will live):\nnano ~/.config/komodo/periphery.config.toml root_directory = \u0026#34;/home/\u0026lt;your_user\u0026gt;/docker\u0026#34; Create the directory as your own user, not via sudo mkdir (otherwise it will be owned by root again, and the permission issues will repeat):\nmkdir -p /home/\u0026lt;your_user\u0026gt;/docker Restart:\nsystemctl --user daemon-reload systemctl --user restart periphery journalctl --user -u periphery -n 30 --no-pager You should see this in the log:\nINFO PeripheryStartup: PeripheryConfig { ... root_directory: \u0026#34;/home/\u0026lt;your_user\u0026gt;/docker\u0026#34;, ... } INFO Logged in to Komodo Core komodo.stilicho.ru websocket as Server immich-host If you\u0026rsquo;ve already gone through onboarding with the old \u0026ldquo;narrow\u0026rdquo; path (as I initially, unknowingly, did) - after changing root_directory, the keys (periphery.key, periphery.pub, core.pub) will be looked for at the new path and won\u0026rsquo;t be there. The simplest fix is to copy them from the old location to the new one, so you don\u0026rsquo;t have to onboard again:\nmkdir -p /home/\u0026lt;your_user\u0026gt;/docker/keys cp /home/\u0026lt;your_user\u0026gt;/.local/share/komodo/keys/* /home/\u0026lt;your_user\u0026gt;/docker/keys/ After that, restarting the service should work without redoing onboarding.\nCheck that the needed folder (in my case, immich) is now visible:\nls /home/\u0026lt;your_user\u0026gt;/docker/immich If the files are visible, you can go back to the Komodo UI and create a Stack for this service exactly the same way we did for local stacks (Server → immich-host, Source → Files on Server, Run Directory → /home/\u0026lt;your_user\u0026gt;/docker/immich, File Paths → your compose file\u0026rsquo;s name - check the exact name via docker compose ls right on that host).\nAlso make sure your user is in the docker group - without this, Periphery won\u0026rsquo;t be able to reach docker.sock:\ngroups $USER sudo usermod -aG docker $USER # if needed - then log back in Checking in the UI # After successful onboarding, the new host will appear in the Komodo UI under the Servers tab with status \u0026ldquo;Connected,\u0026rdquo; with visible metrics (CPU/RAM/disk) and the full container list for that host - including, in my case, Immich. From there you can manage them (deploy, restart, logs) directly from Komodo, without SSHing in.\nDisk Monitoring and Alerts # Komodo can send alerts about disk usage on each connected server. To get the correct size for the root partition specifically (rather than an under/overestimated value due to how counting works), compose.env already has:\nPERIPHERY_INCLUDE_DISK_MOUNTS=/etc/hostname I immediately got an alert like this (the one below is my actual alert):\n{ \u0026#34;name\u0026#34;: \u0026#34;Local\u0026#34;, \u0026#34;path\u0026#34;: \u0026#34;/etc/hostname\u0026#34;, \u0026#34;used_gb\u0026#34;: 178.38, \u0026#34;total_gb\u0026#34;: 228.39 } this isn\u0026rsquo;t a Komodo bug, but an honest message about actual disk usage. I checked what was actually eating up space: docker system df -v sudo du -xh --max-depth=1 / | sort -rh | head -20 Note the -x flag on du - it prevents the command from crossing into other mounted filesystems (e.g., network shares under /mnt), so you only see what\u0026rsquo;s actually taking up space on the local disk. And don\u0026rsquo;t forget sudo - without it, du silently skips directories like /var/lib/docker, which a regular user doesn\u0026rsquo;t have read access to, and the resulting figure will be significantly underestimated.\nIn the end I cleaned up the clutter and the alert went away.\nSummary # We deployed Komodo with:\nMongoDB as the database (without FerretDB/Postgres); bind mounts instead of named volumes for all data; Traefik routing by domain; login via Authentik (OIDC) with a fallback to the local admin; an additional host connected via Periphery as a systemd agent. The main practical lesson of this article is that root_directory/PERIPHERY_ROOT_DIRECTORY needs to be thought through right away, before your first deploy, not after you hit No such file or directory. This restriction applies equally to both the containerized Periphery and the systemd agent (including on remote hosts like my immich-host) - point it right away to the parent directory where all your compose projects on a given host live or will live, not a narrow service folder. I lost a lot of time on this point trying to figure out what was wrong.\nI also described what the interface itself looks like and how to migrate already-running compose stacks into Komodo without downtime.\nStill left out of scope for now are Builds and Repos - i.e., building images straight from git and a full CI/CD workflow. I\u0026rsquo;m planning to record a video about setting up Forgejo as a self-hosted git server and connecting it to Komodo for automatic builds and webhook-triggered deploys - I\u0026rsquo;ll cover that in upcoming articles.\n","date":"August 11, 2026","externalUrl":null,"permalink":"/en/posts/portainer-to-komodo/","section":"Posts","summary":"A step-by-step guide to installing Komodo as a Portainer alternative: docker-compose, MongoDB, bind mounts instead of volumes, login via Authentik (OIDC), and connecting additional hosts via Periphery.","title":"Moving from Portainer to Komodo - Full Installation and Setup","type":"posts"},{"content":"","date":"August 11, 2026","externalUrl":null,"permalink":"/en/tags/portainer/","section":"Tags","summary":"","title":"Portainer","type":"tags"},{"content":"","date":"August 9, 2026","externalUrl":null,"permalink":"/en/tags/collaboration/","section":"Tags","summary":"","title":"Collaboration","type":"tags"},{"content":"","date":"August 9, 2026","externalUrl":null,"permalink":"/en/tags/homelab/","section":"Tags","summary":"","title":"Homelab","type":"tags"},{"content":"","date":"August 9, 2026","externalUrl":null,"permalink":"/en/tags/prohomelab/","section":"Tags","summary":"","title":"ProHomeLab","type":"tags"},{"content":"","date":"August 9, 2026","externalUrl":null,"permalink":"/en/categories/self-hosting---about-the-project/","section":"Categories","summary":"","title":"Self-Hosting - About the Project","type":"categories"},{"content":"","date":"9 August 2026","externalUrl":null,"permalink":"/categories/self-hosting---%D0%BE-%D0%BF%D1%80%D0%BE%D0%B5%D0%BA%D1%82%D0%B5/","section":"Categories","summary":"","title":"Self-Hosting - О Проекте","type":"categories"},{"content":"","date":"9 August 2026","externalUrl":null,"permalink":"/tags/%D1%81%D0%BE%D1%82%D1%80%D1%83%D0%B4%D0%BD%D0%B8%D1%87%D0%B5%D1%81%D1%82%D0%B2%D0%BE/","section":"Tags","summary":"","title":"Сотрудничество","type":"tags"},{"content":"","date":"8 August 2026","externalUrl":null,"permalink":"/tags/firewall/","section":"Tags","summary":"","title":"Firewall","type":"tags"},{"content":" Note Все имена хостов, VLAN и прочее носят условные названия для целей написания настоящей статьи\nРаньше Traefik у меня жил вперемешку со всеми остальными сервисами - контейнером на том же Docker-хосте (условно назовём его Homelab), в той же сети, что и десятки других стэков. Все работало, но с точки зрения безопасности так себе решение: обратный прокси, через который проходит весь внешний трафик и вся аутентификация, ничем не отличался по правам доступа от любого другого контейнера рядом с ним (ко всему прочему большинство контейнеров ещё и в одной docker-сети). Скомпрометируй любой из соседних сервисов - и злоумышленник в одном шаге от единственной точки входа во всю инфраструктуру.\nКо всему прочему сегментация получалась частичной между VLAN, так как надо было выпускать SSL-сертификаты на сервисы в других VLAN. Ломалась сама логика сегментации сети - вроде она, эта ваша сегментация, есть, а вроде и не совсем.\nТак как я решил вынести Traefik физически в отдельный LXC-контейнер (о чём можно почитать здесь, здесь и здесь), то был создан отдельный VLAN и свой собственный периметр в firewall. Заодно вынужденно пересобрал docker-сети и сделал полный аудит правил в OPNsense. Что, забегая вперёд, пошло только на пользу, так как в процессе пересборки сети и контейнеров были выловлены ряд косяков, один из которых был крайне существенным. Признаюсь честно, причиной этого существенного косяка была банальная опечатка, но в случае предметной атаки на мою сеть её последствия могли быть катастрофическими (я не параноик и своё место в истории понимаю, но не вижу смысла игнорировать банальные принципы построения безопасной сети). Ниже - подробное сравнение того, что было и что стало, и почему именно так.\nБыло: четыре сегмента, Traefik растворён в одном из них # До переезда Traefik в отдельный LXC-контейнер в OPNsense было четыре VLAN:\nСегмент Что там жило LAN доверенные устройства, админский доступ WiFi (opt1) бытовые устройства, TV, консоли, мобильные устройства Homelab (opt2) Docker-хосты со всеми стэками, включая сам Traefik на одном из докер-хостов YouTube (opt3) для опытов со съёмками видео для YouTube Никакого выделенного правила именно под reverse-proxy не было - Traefik сидел контейнером в общей docker-сети на Homelab вместе со всем остальным (плюс отдельная сеть proxy, в которую были включены и он, и бэкенды). Firewall-правила сегмента Homelab были написаны в терминах «что Homelab может достать снаружи» (Plex, Postgres, ollama), а не в терминах «кто может достучаться до Traefik и на каких условиях» - потому что такого вопроса просто не стояло: всё было рядом, в одной сети.\nСтало: Traefik - отдельный VLAN со своим набором правил # Добавил пятый сегмент - opt6 (не опечатка в нумерации, есть ещё пара opt-интерфейсов, они неважны для статьи) - только для Traefik и его CrowdSec. Сам Traefik теперь не контейнер, а нативный бинарник (v3.7.0 на дату написания статьи) в LXC на Debian 13, CrowdSec - тоже не в Docker, а через apt, с собственным LAPI и bouncer-плагином, подключённым как experimental plugin в статическом конфиге Traefik. Получилось два независимых экземпляра CrowdSec в инфраструктуре - один плагином прямо в OPNsense, второй - при Traefik.\nLXC закрыл по минимуму: SSH только по ключу, никаких лишних сервисов на хосте. Порт 22 (пока) не менял. Пока не вижу смысла заводить отдельного юзера для traefik.\nБазовые правила на opt6 - по той же схеме, что и на остальных сегментах: разрешить внутренний DNS, дать точечные VPN-исключения там, где они нужны, заблокировать доступ ко всем остальным приватным сетям и только после этого - дефолтный allow в интернет.\nНо главное отличие не в этой стандартной схеме, а в том, что добавилось между её шагами: набор точечных правил Traefik → Homelab:порт_сервиса, по одному на каждый проксируемый сервис, а не одно общее «Traefik видит весь Homelab». Из старого конфига в новом появилось порядка пятидесяти таких правил - например:\nTraefik -\u0026gt; Homelab:Mealie Traefik -\u0026gt; Homelab:Audiobookshelf Traefik -\u0026gt; Homelab:Vaultwarden Traefik -\u0026gt; Homelab:Authentik и так далее, по одному правилу на каждый сервис, стоящий за прокси.\nРаньше, когда Traefik физически был соседом этих контейнеров на одном хосте, такая детализация была не нужна - трафик между ними даже не доходил до firewall, он оставался внутри docker-bridge. Теперь, когда Traefik ушёл на отдельный VLAN, каждое взаимодействие стало пересекать границу сегментов - и firewall наконец увидел (и смог ограничить) то, что раньше было полностью невидимым для него.\nОтдельно осталось одно отключённое правило-заготовка - «Traefik → Homelab без ограничения по порту». Оно выключено, но само его наличие стоит держать под контролем: включать его стоит разве что «на скорую руку» при отладке - и не забывать выключать обратно\nПорт 443 в обратную сторону - не опция, а обязательное условие # Отдельно стоит сказать про направление из остальных VLAN к Traefik - это симметрично важная часть схемы, и без неё вся конструкция не работает. Совсем не работает. Причина достаточно проста: все сервисы у меня имеют SSL-сертификат и общаются по доменным именам.\nЧерез Traefik:443 проходит:\nвся внешняя маршрутизация запросов к сервисам (обычный reverse-proxy трафик); ForwardAuth-проверка через Authentik для любого защищённого ресурса - браузер стучится на сервис, Traefik форвардит запрос в Authentik за решением «пускать/не пускать», и весь этот цикл идёт через тот же 443; OIDC-аутентификация для сервисов, использующих Authentik как провайдера; WSS-соединение Periphery-агентов Komodo с Core - домен komodo.твойдомен.ru резолвится именно в Traefik, и агент инициирует исходящее соединение туда. Поэтому в правилах сегмента Homelab явно прописаны направленные разрешения на 443 порт Traefik - как для самого Homelab, так и для других хостов, которым нужен доступ к сервисам через прокси. Без этого сервисы просто не могу общаться по доменным именам.\nЭто не заплатка на возникшую проблему, а прямое следствие того, что Traefik теперь единая точка входа для всего: и для людей, и для сервисов, и для служебных агентов. Любой VLAN, откуда должен идти запрос к чему-либо через прокси или через Authentik, обязан иметь этот путь открытым - без доступа к 443 разом отваливаются внешняя маршрутизация, вся аутентификация и связь с Periphery-агентами Komodo и аналогичных сервисов (Portainer, Dozzle, Arcane или Dockhand), потому что это на самом деле один и тот же путь трафика, а не три разных. При проектировании любого нового сегмента этот путь нужно закладывать сразу, а не дожидаться, пока что-то перестанет работать.\nDocker-сети: тот же принцип, но внутри одного хоста # В дополнение к описанным правилам firewall, я пересмотрел и сетевую модель на уровне самого Docker. Раньше все стэки на Homelab жили в одной общей docker-сети вместе с Traefik - контейнер одного стэка теоретически мог достучаться до контейнера совсем другого стэка через общий bridge (если он был), и правила firewall тут были бессмысленны, потому что трафик даже не покидал хост.\nТеперь у каждого стэка - своя изолированная docker-сеть, а общую сеть proxy, где раньше сидел реверс-прокси, я отключил: она стала не нужна с тех пор, как Traefik переехал из Docker в LXC и начал ходить к бэкендам не по внутреннему docker-имени, а по IP:порту хоста через firewall - точно так же, как и всё остальное между VLAN. Тот же принцип «точечный доступ вместо общей сети», который применили на уровне VLAN, теперь применяется и на уровне docker-хоста.\nЗачем вообще делать аудит правил, если «и так работает» # Когда экспортировал текущие правила и построчно сравнил со старым конфигом, вылезло несколько вещей, которые в потоке ежедневной работы просто не были бы замечены:\nсамый главный косяк я описать не могу. Не потому что это военная тайна, а потому что стыдно. В описании одного из самых важных правил была допущена досадная описка (даже не опечатка), что фактически приводило к неработающей сегментации. часть добавленных правил была скопирована под новые нужды, но описания за ними я не обновил - например, правила доступа к Traefik:https подписаны как «Allow access to Traefik ping port», хотя к ping-порту (8083) отношения не имеют. Функционально это ничего не ломает, но при следующем аудите легко прочитать неверное описание и сделать неправильный вывод о том, что вообще разрешено. Все переписал; отключённое правило-заготовка на opt6 (см. выше) - зафиксированно отдельно, чтобы не забыть, что оно там есть, но в итоге, уже в процессе написания настоящей статьи, принято решение его просто удалить; ограничил доступ к NAS только портами 445 (протокол smb) и 2049 (протокол nfs) сравнение «было / стало» чётко показало, какие правила - прямое следствие переезда Traefik (весь блок opt6 и связанные с ним :https-разрешения), а какие - унаследованный от старой схемы технический долг, который стоит почистить отдельно. Ничего из этого не было бы заметно, если бы я просто проверил «работает - не работает» и на этом остановился. Ради этого аудит и делается: не чтобы найти одну большую ошибку, а чтобы систематически вычистить мелкие несостыковки, которые накапливаются при любой миграции.\nИтоги # Traefik и CrowdSec - в отдельном LXC на своём VLAN, без лишних соседей Межсегментный доступ к бэкендам - точечный, по конкретным портам под каждый сервис (~50 отдельных правил вместо одного общего) Доступ из остальных VLAN к Traefik:443 - обязательное условие: через него идёт вся внешняя маршрутизация, ForwardAuth, OIDC и связь с Periphery-агентами Komodo одновременно Docker-сети разделены по стэкам, общая сеть под reverse-proxy убрана как избыточная Аудит правил «до/после» оказался полезен сам по себе - как способ систематически найти накопившиеся неточности в конфигурации, которые иначе остались бы незамеченными Если планируете похожий переезд - сначала выпишите все скрытые зависимости через прокси (не только «браузер открывает сайт», но и служебные соединения - агенты, вебхуки, auth-редиректы), и заложите доступ к 443 в обе стороны сразу, а не по факту поломки. И не пожалейте времени на построчное сравнение конфигурации до и после - почти наверняка найдётся что почистить.\n","date":"8 August 2026","externalUrl":null,"permalink":"/posts/my-firewall-rules/","section":"Posts","summary":"Переношу Traefik в отдельный VLAN и перестраиваю сетевую архитектуру homelab: reverse proxy становится центральной точкой доступа к сервисам, а OPNsense контролирует сетевой доступ между VLAN.","title":"Traefik в отдельном VLAN: настройка firewall в OPNsense","type":"posts"},{"content":"","date":"7 August 2026","externalUrl":null,"permalink":"/tags/crowdsec/","section":"Tags","summary":"","title":"CrowdSec","type":"tags"},{"content":" Введение # В части 2 в разделе \u0026ldquo;что осталось\u0026rdquo; я отложил установку CrowdSec на отдельный заход . Вот тот самый заход. CrowdSec ставится в тот же LXC, что и сам Traefik, а не отдельным контейнером в Docker, как было раньше. Это упрощает связность (никаких Docker DNS-имён, всё общается через localhost) и позволяет CrowdSec читать access.log напрямую с диска, без пробрасывания файла между разными окружениями.\nУстановка # CrowdSec ставится через официальный скрипт добавления репозитория, дальше - обычным apt:\ncurl -s https://install.crowdsec.net | sudo sh apt update apt list crowdsec apt install crowdsec apt list crowdsec - необязательный шаг, просто чтобы убедиться, что пакет реально появился в списке после добавления репозитория, прежде чем ставить.\nКоллекции # Коллекция - это готовый набор сценариев обнаружения под конкретный тип нагрузки. Перед установкой обновляю индекс хаба, чтобы точно ставить актуальные версии, а не то, что было зашито в пакет на момент сборки:\ncscli hub update Ставлю сразу пакет под HTTP-периметр (Traefik), плюс базовые сценарии для самой ОС:\ncscli collections install crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/base-http-scenarios crowdsecurity/sshd crowdsecurity/linux crowdsecurity/appsec-generic-rules crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-crs crowdsecurity/traefik - парсер access-логов конкретно под формат Traefik; crowdsecurity/http-cve + base-http-scenarios - обнаружение попыток эксплуатации известных CVE и типовых HTTP-атак; crowdsecurity/sshd + linux - раз CrowdSec теперь живёт в том же LXC, что и Traefik, заодно прикрываю и сам SSH-доступ к контейнеру; appsec-generic-rules, appsec-virtual-patching, appsec-crs - под AppSec-компонент (WAF-подобная защита на уровне запроса, до того как он дойдёт до бэкенда) - про него отдельно ниже. systemctl reload crowdsec Автообновление hub по расписанию # Сценарии и парсеры в хабе периодически обновляются (новые CVE, поправки в существующих детекциях), а вручную про cscli hub update вспоминаешь редко. Выношу в cron-файл, чтобы обновление индекса и апгрейд установленных коллекций происходили сами раз в сутки, в полночь:\nnano /etc/cron.d/crowdsec-hub-update 0 0 * * * root /usr/bin/cscli hub update \u0026amp;\u0026amp; /usr/bin/cscli hub upgrade Файл в /etc/cron.d/ не требует crontab -e и не привязан к пользовательскому crontab - подхватывается системным cron автоматически после сохранения, без дополнительной перезагрузки демона. hub upgrade подтягивает новые версии уже установленных коллекций/парсеров/сценариев (не ставит новые - только обновляет то, что уже включено). Если апгрейд что-то реально поменял, cscli сам попросит systemctl reload crowdsec - это можно либо добавить третьей командой в ту же строку cron, либо, как я предпочитаю, оставить на ручной контроль, чтобы не перезагружать конфигурацию боевого сервиса без просмотра, что именно обновилось.\nПрофиль реагирования # Профиль определяет, что конкретно делать, когда CrowdSec принимает решение о блокировке - не просто \u0026ldquo;забанить\u0026rdquo;, а по какой логике и куда уведомить.\nnano /etc/crowdsec/profiles.yaml:\nname: default_ip_remediation filters: - Alert.Remediation == true \u0026amp;\u0026amp; Alert.GetScope() == \u0026#34;Ip\u0026#34; decisions: - type: ban duration: 4h notifications: - http_default on_success: break --- name: default_range_remediation filters: - Alert.Remediation == true \u0026amp;\u0026amp; Alert.GetScope() == \u0026#34;Range\u0026#34; decisions: - type: ban duration: 4h notifications: - http_default on_success: break Два профиля - один на бан конкретного IP, другой на бан целого диапазона (если атака идёт распределённо с одной подсети). Оба банят на 4 часа и шлют уведомление через плагин http_default, который настраивается отдельно.\nУведомления через Gotify # Раз у меня в стеке уже есть Gotify (пуш-уведомления на телефон/десктоп) - логично заводить туда и алерты CrowdSec, вместо того чтобы заново поднимать email-интеграцию (другие варианты в России на дату написания статьи официально не работают).\nnano /etc/crowdsec/notifications/http.yaml:\ntype: http name: http_default log_level: info format: | {{ range . -}} {{ $alert := . -}} { \u0026#34;extras\u0026#34;: { \u0026#34;client::display\u0026#34;: { \u0026#34;contentType\u0026#34;: \u0026#34;text/markdown\u0026#34; } }, \u0026#34;priority\u0026#34;: 3, {{range .Decisions -}} \u0026#34;title\u0026#34;: \u0026#34;{{.Type }} {{ .Value }} for {{.Duration}}\u0026#34;, \u0026#34;message\u0026#34;: \u0026#34;{{.Scenario}} \\n\\n[crowdsec cti](https://app.crowdsec.net/cti/{{.Value -}}) \\n\\n[shodan](https://shodan.io/host/{{.Value -}})\u0026#34; {{end -}} } {{ end -}} url: https://gotify.domain.ru/message method: POST headers: X-Gotify-Key: ваш_application_token Content-Type: application/json Шаблон формирует Gotify-совместимый JSON: заголовок с типом и значением решения (IP/диапазон, длительность бана), тело сообщения со сценарием, который сработал, плюс сразу готовые ссылки на CrowdSec CTI и Shodan для быстрой проверки адреса вручную.\nX-Gotify-Key - это application token конкретного приложения в Gotify (создаётся в его собственном UI), не токен пользователя.\nИсточники логов (acquisition) # CrowdSec с версии, которую мы ставим, использует директорию /etc/crowdsec/acquis.d/ - отдельный файл на каждый источник, вместо одного монолитного acquis.yaml. Логика та же, что и с разбивкой dynamic/ у самого Traefik: читать и поддерживать проще, когда источники не свалены в одну кучу.\nAccess-логи Traefik # touch /etc/crowdsec/acquis.d/traefik.yaml poll_without_inotify: false filenames: - /var/log/traefik/*.log labels: type: traefik poll_without_inotify: false - использовать inotify (эффективнее, чем поллинг файла по таймеру) для отслеживания новых строк в логе.\nЧерез маску *.log в этот источник попадает не только access.log, но и traefik.log (операционный лог самого Traefik - запуск, обновление конфигурации, выпуск TLS-сертификатов). Парсер crowdsecurity/traefik-logs рассчитан на формат access-лога, поэтому строки из traefik.log в cscli metrics будут честно показываться как \u0026ldquo;unparsed\u0026rdquo; - это ожидаемо, не ошибка конфигурации, и убирать traefik.log из источника необязательно.\nСистемные логи # touch /etc/crowdsec/acquis.d/syslog.yaml filenames: - /var/log/auth.log - /var/log/syslog labels: type: syslog Это то, ради чего ставили коллекции sshd/linux - раз CrowdSec теперь в том же LXC, что принимает внешний трафик, разумно заодно приглядывать за попытками подбора SSH и подозрительной активностью на уровне ОС.\nDebian 13 (trixie): rsyslog не ставится по умолчанию # На Debian 13 этот источник сам по себе работать не будет. Начиная с bookworm rsyslog больше не ставится по умолчанию - /var/log/auth.log и /var/log/syslog просто не существуют или не пишутся, если пакет не установлен явно. Проверить:\nls -la /var/log/auth.log /var/log/syslog Если auth.log отсутствует, а syslog есть, но нулевого размера - rsyslog не установлен:\napt install rsyslog systemctl enable --now rsyslog Дальше - ловушка конкретно для trixie: даже после установки пакет не создаёт файл с правилами маршрутизации /etc/rsyslog.d/50-default.conf, который раньше шёл \u0026ldquo;из коробки\u0026rdquo;. Каталог /etc/rsyslog.d/ после установки пуст (кроме, возможно, postfix.conf, если Postfix тоже стоит). Без этих правил rsyslogd слушает журнал, но не знает, куда писать auth/authpriv-сообщения - файлы остаются пустыми. Создаём вручную:\nnano /etc/rsyslog.d/50-default.conf Минимум, нужный CrowdSec:\nauth,authpriv.* /var/log/auth.log *.*;auth,authpriv.none -/var/log/syslog systemctl restart rsyslog Проверка - любое действие через sudo (например sudo -k \u0026amp;\u0026amp; sudo whoami, чтобы сбросить кэш и заново пройти PAM) должно тут же появиться в auth.log:\nls -la /var/log/auth.log /var/log/syslog Оба файла должны существовать и расти. После этого systemctl restart crowdsec и cscli metrics - в Acquisition Metrics должны появиться строки file:/var/log/auth.log и file:/var/log/syslog с ненулевым числом прочитанных строк.\nsystemctl reload crowdsec cscli metrics cscli metrics показывает, видит ли CrowdSec вообще какие-то строки из подключённых источников - если счётчики нулевые, то AppSec можно не начинать настраивать, сначала надо разобраться с acquisition.\nAppSec-компонент # AppSec - это WAF-подобная защита на уровне самого запроса (сигнатуры атак, virtual patching под известные CVE), работающая отдельно от классического anti-bruteforce анализа логов. Traefik обращается к нему напрямую через bouncer-плагин, до того как запрос уйдёт к реальному бэкенду.\ntouch /etc/crowdsec/acquis.d/appsec.yaml listen_addr: 127.0.0.1:7422 appsec_config: crowdsecurity/appsec-default name: myAppSecComponent source: appsec labels: type: appsec Важно проверить перед стартом: адрес обязательно 127.0.0.1, не 127.0.0.0 - последний является адресом самой сети 127.0.0.0/8, а не хостом, и не гарантированно забиндится корректно. В bouncer-плагине Traefik ниже используется localhost:7422, что резолвится в 127.0.0.1 - оба адреса должны совпадать буквально, иначе AppSec будет недоступен, а crowdsecAppsecUnreachableBlock: true в конфиге плагина заблокирует вообще весь трафик через Traefik, если компонент не отвечает. systemctl reload crowdsec systemctl reload traefik cscli metrics show acquisition Регистрация bouncer\u0026rsquo;а и подключение к Traefik # cscli bouncers add traefik-bouncer Команда выведет API-ключ один раз - сохраните сразу, повторно посмотреть не получится (та же логика, что с токеном Cloudflare в части 2), только пересоздать заново.\nMiddleware в dynamic/middlewares/crowdsec.yaml:\nhttp: middlewares: crowdsec: plugin: bouncer: enabled: true logLevel: INFO updateIntervalSeconds: 15 updateMaxFailure: 0 defaultDecisionSeconds: 15 httpTimeoutSeconds: 10 crowdsecMode: stream crowdsecAppsecEnabled: true crowdsecAppsecHost: localhost:7422 crowdsecAppsecFailureBlock: true crowdsecAppsecUnreachableBlock: true crowdsecLapiKey: ваш_ключ_из_cscli_bouncers_add crowdsecLapiHost: localhost:8080 crowdsecLapiScheme: http forwardedHeadersTrustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 clientTrustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 localhost вместо Docker-имени вроде crowdsec:8080, которое было бы в старой Docker-based установке - оба сервиса теперь в одном LXC, дополнительная сетевая связность не нужна вообще.\nПоследний шаг - раскомментировать middleware в static config (в части 2 он был закомментирован):\nentryPoints: web: http: middlewares: - crowdsec@file # теперь можно раскомментировать - rate-limit@file websecure: http: middlewares: - crowdsec@file # и здесь - rate-limit@file systemctl restart traefik Проверка # cscli decisions list # текущие активные баны cscli metrics # общая статистика по сценариям и bouncer\u0026#39;ам cscli bouncers list # подтверждение, что traefik-bouncer подключился и опрашивает LAPI Если cscli bouncers list показывает bouncer, но с давним временем последнего запроса - проверьте связность между Traefik и localhost:8080 (сам факт, что оба в одном LXC, ещё не гарантирует, что плагин смотрит на правильный порт/схему).\nСсылки # Документация CrowdSec crowdsec-bouncer-traefik-plugin Список коллекций CrowdSec Hub ","date":"7 August 2026","externalUrl":null,"permalink":"/posts/traefik-in-lxc-part-3/","section":"Posts","summary":"Третья часть серии про Traefik в LXC - установка CrowdSec в тот же контейнер, что и сам Traefik. Коллекции сценариев, профиль реагирования с уведомлениями в Gotify, источники логов (Traefik, syslog, AppSec), и подключение bouncer-плагина обратно к Traefik.","title":"Установка Traefik в LXC-контейнер Proxmox как systemd-сервиса | Часть 3 - CrowdSec","type":"posts"},{"content":" What middleware in Traefik is # When a request reaches the Traefik reverse proxy, it passes through a processing chain before reaching the actual service (your application behind the proxy) - or instead gets a response directly from Traefik itself, without ever reaching the backend. Middleware is exactly the mechanism that lets you intervene in the request or response along this path: modify headers, reject the request, throttle the rate of requests, require authentication, rewrite the path, and so on.\nEssentially, middleware in Traefik is a direct analogue of middleware in any web framework (Express, Django, ASP.NET) - just at the reverse-proxy level rather than the application level. The difference matters: Traefik\u0026rsquo;s middleware runs before the request ever reaches your service, which means it can protect an application that has no protection of its own (no authentication, no rate limiting, no header validation).\nWhy bother, if you can configure all of this in the application itself # Formally, a lot of what middleware does can also be implemented on the application side. But there are reasons why doing it at the proxy level is more convenient and more correct from a management and security standpoint:\nCentralization. Rate limiting, basic authentication, security headers - if all of this is configured once in Traefik, you don\u0026rsquo;t need to repeat the logic in every individual application, some of which don\u0026rsquo;t even offer that capability. Consistency. The same policy (for example, security headers) is applied to all services at once, without the risk of forgetting it somewhere. Protecting what can\u0026rsquo;t protect itself. Many self-hosted applications (dashboards, simple utilities) have no built-in authentication at all - a middleware like forwardAuth or basicAuth in front of such a service closes that gap without touching the application\u0026rsquo;s own code. Separation of concerns. The application handles its own direct task, while questions like \u0026ldquo;who is allowed in here\u0026rdquo; and \u0026ldquo;how often can they knock\u0026rdquo; are resolved at the infrastructure level. How middleware is applied to a request # Middleware doesn\u0026rsquo;t work on its own - it\u0026rsquo;s declared in the dynamic config, and then attached to a specific router by name:\nhttp: routers: my-service: rule: \u0026#34;Host(`app.example.com`)\u0026#34; middlewares: - default-headers - rate-limit service: my-service middlewares: default-headers: headers: frameDeny: true rate-limit: rateLimit: average: 100 Order in the list matters. Middlewares are applied sequentially, top to bottom - the request passes through default-headers, then through rate-limit, and only after that (if none of the middlewares rejected it) reaches the service. The response goes in the reverse order. This matters, for example, for authentication - a middleware that checks access should generally come before ones that simply modify headers, otherwise an unauthorized request might manage to touch something before it\u0026rsquo;s rejected.\nThe same middleware can be reused across any number of routers - you declare it once and attach it anywhere by name. When using multiple providers (file provider, Docker provider), the provider suffix is appended to the name: authentik@file, redirect@docker - this is how Traefik distinguishes between identically named middlewares declared in different backends.\nDefining and applying are not the same thing # Middleware is always defined in the dynamic config - its type and parameters (headers, rateLimit, forwardAuth, etc.) can\u0026rsquo;t be described directly in the static config (traefik.yaml); that option simply doesn\u0026rsquo;t exist there. But an already-defined middleware can be applied in two different ways.\nSelectively, to a specific router - as in the example above:\n# dynamic config http: routers: my-service: middlewares: - default-headers - authentik In this example we first apply the standard request headers, and then redirect the request to Authentik\nGlobally, via the entryPoint in the static config. In traefik.yaml you can reference a middleware by name (with the provider suffix), and it will then be applied to all requests passing through that entrypoint, before Traefik even figures out which router the request belongs to:\n# traefik.yaml (static config) entryPoints: websecure: address: \u0026#34;:443\u0026#34; http: middlewares: - rate-limit@file The middleware is still defined in the dynamic config - the static config only holds a reference to its name. This approach is convenient for things that should apply uniformly to all traffic (rate limit, the CrowdSec bouncer) - you don\u0026rsquo;t need to list them in the middlewares: section of every individual service router, since they\u0026rsquo;re already applied globally through the entrypoint binding.\nWhat a Chain is # A Chain is a middleware that itself consists of other middlewares:\nhttp: middlewares: secured: chain: middlewares: - default-whitelist - default-headers You attach the secured chain to a router - and get both (default-whitelist, then default-headers) applied in the given order, in one line. Convenient when the same combination of several middlewares repeats across many routers - instead of listing the whole set every time, you reference a single chain.\nOpen-source version vs Traefik Hub # Some of the middlewares in the Traefik documentation are marked as available only in Traefik Hub (the paid add-on/Enterprise) - for example, JWT, OIDC, OAuth2, OPA, WAF, LDAP, HMAC, APIKey, Distributed RateLimit. Below are only the middlewares available in the open-source version that most homelab setups (including mine) actually use.\nFull list of middlewares # AddPrefix # Adds a prefix to the request path before it goes to the backend. Useful when the backend expects a path like /api/..., but you want to expose it without the prefix externally.\nhttp: middlewares: add-prefix-example: addPrefix: prefix: \u0026#34;/api\u0026#34; BasicAuth # Classic HTTP Basic Authentication - a login/password dialog in the browser. The password hash is generated via htpasswd (from the apache2-utils package):\nhtpasswd -nB username http: middlewares: basic-auth-example: basicAuth: users: - \u0026#34;username:$2y$05$...\u0026#34; realm: \u0026#34;Restricted\u0026#34; I use this to protect the Traefik dashboard itself - a simple and reliable fallback that doesn\u0026rsquo;t depend on an external identity provider being available.\nBuffering # Buffers the request/response body before passing it on - useful for applications with large files (document, photo, video uploads) and for configuring retries on network errors.\nhttp: middlewares: middlewares-buffering: buffering: maxRequestBodyBytes: 10485760 memRequestBodyBytes: 2097152 maxResponseBodyBytes: 10485760 memResponseBodyBytes: 2097152 retryExpression: \u0026#34;IsNetworkError() \u0026amp;\u0026amp; Attempts() \u0026lt;= 2\u0026#34; I keep this as a template for services with large uploads (Nextcloud, Immich, OnlyOffice), though it isn\u0026rsquo;t attached to any of them directly yet.\nChain # We already covered this above - it combines several middlewares under one name.\nhttp: middlewares: secured: chain: middlewares: - default-whitelist - default-headers CircuitBreaker # Automatically cuts off traffic to a service if it starts returning mass errors or slowing down - protects the rest of the system from a cascading effect caused by one failing backend.\nhttp: middlewares: circuit-breaker-example: circuitBreaker: expression: \u0026#34;NetworkErrorRatio() \u0026gt; 0.30 || ResponseCodeRatio(500, 600, 0, 600) \u0026gt; 0.25\u0026#34; checkPeriod: \u0026#34;10s\u0026#34; fallbackDuration: \u0026#34;30s\u0026#34; recoveryDuration: \u0026#34;30s\u0026#34; Compress # Compresses the response body (gzip) before sending it to the client - saves bandwidth. It\u0026rsquo;s worth excluding already-compressed formats (images, video) - compressing them again is pointless, they\u0026rsquo;re already compressed, and it just wastes CPU cycles.\nhttp: middlewares: compress: compress: excludedContentTypes: - \u0026#34;image/png\u0026#34; - \u0026#34;image/jpeg\u0026#34; - \u0026#34;image/webp\u0026#34; - \u0026#34;video/mp4\u0026#34; ContentType # In Traefik v3, Content-Type auto-detection is enabled by default - this middleware is only needed if you want to explicitly disable auto-detection for a specific service.\nhttp: middlewares: content-type-example: contentType: {} DigestAuth # Similar to BasicAuth, but the password is never transmitted in plain form, even within the HTTP scheme (a hash-based challenge-response is used).\nhttp: middlewares: digest-auth-example: digestAuth: users: - \u0026#34;username:Restricted:ha1_hash\u0026#34; realm: \u0026#34;Restricted\u0026#34; Errors (Custom Error Pages) # Replaces the default Traefik/backend error page with your own - serving it from a separate service (for example, a static page).\nhttp: middlewares: error-pages-example: errors: status: - \u0026#34;500-599\u0026#34; service: error-pages-service query: \u0026#34;/{status}.html\u0026#34; ForwardAuth # One of the most useful middlewares for a homelab with SSO. Redirects each incoming request to an external authentication service (in my case, Authentik) before letting it through. If the external service responds with success - the request goes to the real backend, with headers added from the response (username, groups, etc.); if not - Traefik itself returns the authentication response (redirect to login), without touching the backend at all.\nhttp: middlewares: authentik: forwardAuth: address: \u0026#34;http://10.10.10.10:9000/outpost.goauthentik.io/auth/traefik\u0026#34; trustForwardHeader: true maxResponseBodySize: 1048576 authResponseHeaders: - X-authentik-username - X-authentik-groups - X-authentik-email - X-authentik-name - X-authentik-uid An important nuance: this is only needed for applications that don\u0026rsquo;t know how to talk to an identity provider directly (via OIDC). If an application supports an OIDC client itself (as many modern self-hosted services do) - forwardAuth isn\u0026rsquo;t needed; the application is configured directly against Authentik as an Identity Provider, without Traefik being involved in the authentication chain.\nIt should also be noted that not every authentication service can work with forwardAuth directly. Authentik and Authelia can; Keycloak, as of the time of writing, doesn\u0026rsquo;t have this built in out of the box.\nGrpcWeb # Relevant only if you\u0026rsquo;re proxying a grpc-web client to a regular gRPC backend - converts the protocol on the fly.\nhttp: middlewares: grpc-web-example: grpcWeb: allowOrigins: - \u0026#34;*\u0026#34; Headers # One of the most commonly used middlewares - manages HTTP headers on the request and response: security headers (HSTS, X-Frame-Options, CSP), custom headers, CORS.\nhttp: middlewares: default-headers: headers: frameDeny: true browserXssFilter: true contentTypeNosniff: true forceSTSHeader: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 15552000 customFrameOptionsValue: SAMEORIGIN customRequestHeaders: X-Forwarded-Proto: https I keep two baseline variants - a lighter one for most services and a hardened one (hiding the server version, longer HSTS for the preload list) for more sensitive cases - plus separate variants for specific applications that need a non-standard CSP (for example, to embed a document editor in an iframe from a different domain).\nInFlightReq # Limits the number of concurrent connections (as opposed to rate limit, which limits requests per second). Useful for resource-intensive endpoints - for example, video transcoding in Immich (Plex or Jellyfin can already limit concurrent streams on their own).\nhttp: middlewares: in-flight-req-example: inFlightReq: amount: 20 IPAllowList # Restricts access by a list of allowed IPs/subnets.\nhttp: middlewares: default-whitelist: IPAllowList: sourceRange: - \u0026#34;10.0.0.0/8\u0026#34; - \u0026#34;192.168.0.0/16\u0026#34; - \u0026#34;172.16.0.0/12\u0026#34; All of my services are locked behind authentication, so this middleware isn\u0026rsquo;t currently attached anywhere - I keep it as a ready-to-use tool just in case.\nPassTLSClientCert # Relevant for mTLS scenarios, where the backend itself wants to see the client certificate in a header.\nhttp: middlewares: pass-tls-client-cert-example: passTLSClientCert: pem: true RateLimit # Limits the request rate from a single client (by default, by source IP) - protection against flooding/DDoS.\nhttp: middlewares: rate-limit: rateLimit: average: 100 burst: 50 I have this attached globally on both entrypoints (web/websecure), rather than selectively per service - a general line of defense for all traffic.\nRedirectScheme # Redirects a request from one scheme to another - most often HTTP → HTTPS.\nhttp: middlewares: https-redirect: redirectScheme: scheme: https permanent: true RedirectRegex # The same thing, but with an arbitrary regex pattern for more complex redirects, not just scheme changes.\nhttp: middlewares: redirect-regex-example: redirectRegex: regex: \u0026#34;^https://(.*)/old-path\u0026#34; replacement: \u0026#34;https://${1}/new-path\u0026#34; permanent: true ReplacePath # Completely replaces the request path before passing it to the backend.\nhttp: middlewares: replace-path-example: replacePath: path: \u0026#34;/new/path\u0026#34; ReplacePathRegex # The same thing via regex, with the ability to capture and reuse parts of the original path.\nhttp: middlewares: replace-path-regex-example: replacePathRegex: regex: \u0026#34;^/old/(.*)\u0026#34; replacement: \u0026#34;/new/$${1}\u0026#34; Retry # Retries the request on a network error up to a set number of attempts - unlike retryExpression inside buffering, this is a separate, more general mechanism.\nhttp: middlewares: retry-example: retry: attempts: 3 initialInterval: \u0026#34;100ms\u0026#34; StripPrefix # Removes a given prefix from the path before passing it to the backend - the reverse of AddPrefix.\nhttp: middlewares: strip-prefix-example: stripPrefix: prefixes: - \u0026#34;/api\u0026#34; StripPrefixRegex # The same thing, but using a regex pattern.\nhttp: middlewares: strip-prefix-regex-example: stripPrefixRegex: regex: - \u0026#34;^/api/v[0-9]+\u0026#34; How I organized middleware in my own setup # Each middleware is a separate .yaml file at /etc/traefik/dynamic/middlewares/, with the filename matching its purpose. Some middlewares are actually attached to services (default-headers, rate-limit, https-redirect, the authentik forwardAuth), while some I keep as a ready-made library on standby - for whenever a specific scenario comes up (a whitelist for admin panels, buffering for uploads, an in-flight limit for transcoding), without having to invent the config from scratch on the spot.\nThe key benefit of this approach is that when adding a new service, I don\u0026rsquo;t need to think \u0026ldquo;how does this middleware even get written\u0026rdquo; - I just grab the ready-made file, copy the relevant lines into services/\u0026lt;new-service\u0026gt;.yaml, and attach it by name.\nLinks # Official list of Traefik middlewares ForwardAuth Headers ","date":"August 6, 2026","externalUrl":null,"permalink":"/en/posts/traefik-middlewares-overview/","section":"Posts","summary":"Middleware is the second most important building block of Traefik after routers. In this article I break down what it is, why it’s needed, how it’s applied, what a chain is, and I go through all the middlewares from the open-source version of Traefik with the configuration examples I use myself.","title":"Middlewares in Traefik - what they are, why you need them, and the full list for a homelab","type":"posts"},{"content":"","date":"August 6, 2026","externalUrl":null,"permalink":"/en/tags/reverse-proxy/","section":"Tags","summary":"","title":"Reverse-Proxy","type":"tags"},{"content":"","date":"August 6, 2026","externalUrl":null,"permalink":"/en/categories/traefik/","section":"Categories","summary":"","title":"Traefik","type":"categories"},{"content":"A series of articles about setting up and using Traefik — a modern reverse proxy and load balancer.\nWe cover installation in Docker and LXC, SSL configuration, routing, Let\u0026rsquo;s Encrypt integration, and secure microservice management.\n","date":"August 6, 2026","externalUrl":null,"permalink":"/en/posts/traefik/","section":"Posts","summary":"A series of articles about setting up and using Traefik — a modern reverse proxy and load balancer. We cover installation in Docker and LXC, SSL configuration, routing, Let’s Encrypt integration, and secure microservice management.","title":"Traefik","type":"posts"},{"content":"","date":"August 6, 2026","externalUrl":null,"permalink":"/en/series/traefik/","section":"Series","summary":"","title":"Traefik","type":"series"},{"content":"","date":"August 6, 2026","externalUrl":null,"permalink":"/en/tags/traefik/","section":"Tags","summary":"","title":"Traefik","type":"tags"},{"content":" Введение # В первой части мы подготовили LXC-контейнер, поставили Traefik как бинарник и запустили его в тестовом режиме - с открытым dashboard и DEBUG-логами, только чтобы убедиться, что всё в принципе стартует. Как вы наверно поняли, конкретно в моем случае, речь идет о переезде рабочего конфига, а не о создании с нуля, поэтому часть статьи написана с учетом данной специфики.\nС тех пор проделана основная часть работы: финальный static config, TLS-сертификаты, ротация логов и полная раскладка dynamic config по файлам - включая перенос десятка сервисов, которые раньше маршрутизировались через Docker labels, а не через Traefik file provider.\nСам по себе переезд на новый хост закономерно потребовал построчно пройтись по всей конфигурации - и по сути превратился в полноценный аудит. В процессе всплыло немало интересного: и про сам Traefik, и про то, как были устроены отдельные сервисы вокруг него. Но давайте обо всем по порядку.\nПолучение API-токена Cloudflare # Прежде чем собирать финальный static config, нужен API-токен Cloudflare - он понадобится для DNS-01 challenge при выпуске сертификатов (в том числе wildcard, без необходимости открывать порт 80 наружу под HTTP-01).\nКонечно не обязательно пользоваться Cloudflare, можно использовать любого днс-провайдера, с которым работает DNS Providers :: ACME client and library written in Go.\nПереходим в профиль Cloudflare, в раздел создания токенов.\nВыбираем создание кастомного токена - не готовый шаблон, чтобы ограничить права минимально необходимым набором, а не выдавать токену больше, чем реально нужно.\nУказываем права: Zone → DNS → Edit, и по возможности ограничиваем токен конкретной зоной (доменом), а не всеми зонами аккаунта сразу - так при компрометации токена ущерб ограничен одним доменом.\nСоздаём токен.\nЗначение токена показывается только один раз - сохраните его сразу в менеджере паролей. Посмотреть его повторно через интерфейс Cloudflare не получится, только пересоздать заново.\nСписок уже созданных токенов доступен там же, на странице токенов.\nЭтот токен и есть значение CF_DNS_API_TOKEN, которое пойдёт в traefik.env - подробнее в разделе про TLS ниже.\nФинальный static config # Отличия от тестового варианта из части 1:\nglobal: # Глобальные настройки Traefik. checkNewVersion: true # При запуске Traefik проверяет, вышла ли новая версия. sendAnonymousUsage: true # Отправляет анонимную телеметрию разработчикам Traefik. # Никакие конфигурации или домены не передаются. # Можно отключить, если принципиально не используете телеметрию. api: # Настройки встроенного API и веб-интерфейса. dashboard: true # Включает Dashboard для просмотра роутеров, # сервисов, middleware и состояния Traefik. debug: true # Разрешает расширенную диагностическую информацию API. # Безопасно, если Dashboard защищён авторизацией # и не опубликован в Интернет без защиты. entryPoints: # Точки входа - порты, на которых слушает Traefik. web: # HTTP (порт 80). address: \u0026#34;:80\u0026#34; # Прослушивать все интерфейсы на TCP-порту 80. forwardedHeaders: # Настройки доверенных X-Forwarded-* заголовков. trustedIPs: \u0026amp;trustedIps # YAML-якорь. Позже этот список будет повторно использован # для HTTPS без дублирования. # Cloudflare public IP list - 103.21.244.0/22 # Разрешить доверять X-Forwarded-* только запросам, # пришедшим с IP Cloudflare. # ... остальные диапазоны Cloudflare http: # Настройки HTTP для данного entryPoint. encodedCharacters: # Разрешить некоторые URL в закодированном виде. allowEncodedSlash: true # Не декодировать \u0026#34;%2F\u0026#34; в \u0026#34;/\u0026#34;. # Нужно некоторым приложениям и API. allowEncodedHash: true # Не декодировать \u0026#34;%23\u0026#34; в \u0026#34;#\u0026#34;. # Иногда требуется REST API и WebDAV. middlewares: # Middleware, применяемые ко всем HTTP-запросам. # - crowdsec@file # После установки CrowdSec можно включить # глобальную защиту от известных атакующих IP. - rate-limit@file # Ограничение количества запросов. # Защищает от простого флуда и перебора. redirections: # Правила автоматических перенаправлений. entryPoint: # Перенаправление между entryPoint. to: websecure # Все HTTP-запросы отправлять на HTTPS. scheme: https # Использовать HTTPS. websecure: # HTTPS (порт 443). address: \u0026#34;:443\u0026#34; # Прослушивать TCP-порт 443. forwardedHeaders: trustedIPs: *trustedIps # Использовать тот же список доверенных IP, # который объявлен выше. http: encodedCharacters: allowEncodedSlash: true # Аналогично HTTP. allowEncodedHash: true # Аналогично HTTP. middlewares: # - crowdsec@file - rate-limit@file # Ограничение запросов также работает и по HTTPS. transport: # Таймауты обработки соединений. respondingTimeouts: readTimeout: 600s # Максимальное время чтения запроса клиента. # Полезно для больших загрузок. writeTimeout: 600s # Максимальное время отправки ответа. idleTimeout: 600s # Через сколько закрывать неактивное соединение. metrics: # Отдельный entryPoint для Prometheus. address: \u0026#34;:8082\u0026#34; # Метрики доступны только на порту 8082. metrics: # Настройки экспорта метрик. prometheus: # Использовать формат Prometheus. entryPoint: metrics # Отдавать метрики через entryPoint metrics. addEntryPointsLabels: true # Добавлять метку entryPoint в метрики. addServicesLabels: true # Добавлять имя backend-сервиса. addRoutersLabels: true # Добавлять имя router. buckets: # Границы гистограмм времени ответа. - 0.1 # До 100 мс. - 0.3 # До 300 мс. - 1.2 # До 1.2 секунды. - 5.0 # До 5 секунд. serversTransport: # Настройки подключения Traefik к backend. insecureSkipVerify: false # Проверять TLS-сертификаты backend. # Это правильное значение. # Для отдельных сервисов можно создать # собственный ServersTransport. providers: # Источники конфигурации. file: # Использовать файловый provider. directory: /etc/traefik/dynamic # Каталог с динамической конфигурацией. watch: true # Автоматически применять изменения без перезапуска. certificatesResolvers: # Настройки получения сертификатов. cloudflare: # Имя resolver. acme: # Использовать ACME (Let\u0026#39;s Encrypt). email: email@email.com # Email владельца сертификатов. storage: /etc/traefik/acme.json # Где хранить сертификаты и аккаунт ACME. dnsChallenge: # Подтверждение владения доменом через DNS. provider: cloudflare # Использовать Cloudflare API. resolvers: # DNS-серверы, через которые проверяется TXT-запись. - \u0026#34;1.1.1.1:53\u0026#34; - \u0026#34;1.0.0.1:53\u0026#34; log: # Основной журнал Traefik. level: \u0026#34;INFO\u0026#34; # Уровень логирования. # DEBUG полезен только при поиске проблем. filePath: \u0026#34;/var/log/traefik/traefik.log\u0026#34; # Путь к файлу логов. format: \u0026#34;common\u0026#34; # Классический текстовый формат. maxSize: 100 # Ротация после достижения 100 МБ. maxBackups: 0 # Хранить все архивы. maxAge: 0 # Не удалять старые архивы по возрасту. compress: true # Сжимать старые файлы логов. accessLog: # Журнал всех HTTP-запросов. filePath: \u0026#34;/var/log/traefik/access.log\u0026#34; format: json # JSON удобно анализировать через Loki, # Elasticsearch и Grafana. addInternals: true # Логировать внутренние сервисы Traefik # (Dashboard, Ping и т.п.). filters: # Фильтрация записей. statusCodes: - \u0026#34;204-299\u0026#34; # Логировать успешные ответы. - \u0026#34;400-599\u0026#34; # Логировать ошибки клиента и сервера. fields: headers: defaultMode: drop # По умолчанию не сохранять HTTP-заголовки. names: User-Agent: keep # Оставить только User-Agent. experimental: # Экспериментальные возможности. plugins: # Подключение сторонних плагинов. bouncer: # CrowdSec Bouncer. moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin # GitHub-модуль плагина. version: v1.7.1 # Фиксированная версия. traefikwarp: # Плагин интеграции с Cloudflare WARP. moduleName: github.com/l4rm4nd/traefik-warp version: v1.1.5 tls: # Глобальные настройки TLS. options: default: # Настройки по умолчанию для всех HTTPS-соединений. sniStrict: true # Запрещать TLS-соединение без корректного SNI. # Повышает безопасность. minVersion: VersionTLS12 # Минимально допустимая версия TLS. # TLS 1.0 и 1.1 полностью запрещаются. cipherSuites: # Разрешённые шифры (используются только TLS 1.2). # Для TLS 1.3 список игнорируется, # так как он фиксирован стандартом. - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 Главное, что поменялось относительно тестового конфига из первой части:\nproviders.docker убран полностью - цель всего переезда как раз в отвязке от Docker и любого другого бекэнда в принципе; api.insecure больше не используется - dashboard защищён отдельным роутером с Basic Auth (см. раздел ниже), а не голым портом 8080; log.level вернул на INFO - DEBUG был нужен только для первого теста. Про api.debug: true # Оставил осознанно. Это включает pprof-эндпоинты рядом с dashboard - сам по себе некритично, если роутер к api@internal защищён аутентификацией (Basic Auth или Authentik), что у меня и сделано.\nПро allowEncodedSlash/allowEncodedHash # Не убирал, хотя формально это дублирует дефолтное поведение Traefik. У этих флагов нестабильная история между релизами v3 - дефолт менялся туда-обратно между минорными версиями, менялся разработчиками молча, что приводило к неработоспособным приложениям, типа Matrix или Trilium. Явная фиксация в конфиге страхует от неожиданностей при обновлении бинарника.\nTLS: один wildcard-сертификат вместо кучи отдельных # Вместо того чтобы прописывать certResolver в каждом сервисном роутере отдельно, вынес это в отдельный файл dynamic/tls.yaml:\nnano /etc/traefik/dynamic/tls.yml tls: stores: default: defaultGeneratedCert: resolver: cloudflare domain: main: domain.ru sans: - \u0026#34;*.domain.ru\u0026#34; defaultGeneratedCert задаёт сертификат по умолчанию для всего Traefik. Любой роутер с tls: {} (без явных domains/certResolver) автоматически получает этот wildcard-сертификат по SNI - не нужно дублировать резолвер в каждом из полутора десятков сервисных файлов.\nТокен Cloudflare, полученный в самом начале статьи, для DNS-01 challenge вынесен из static config в отдельный EnvironmentFile:\nsudo touch /etc/traefik/traefik.env sudo chmod 600 /etc/traefik/traefik.env # /etc/traefik/traefik.env, права 600 CF_DNS_API_TOKEN=ваш_токен и подключён в systemd-юните через EnvironmentFile= - подробнее в разделе про юнит ниже.\nDashboard: защита через Basic Auth # Раз api.insecure больше не используется, доступ к dashboard идёт через обычный роутер - точно так же, как к любому проксируемому сервису, только с обязательным middleware аутентификации на нём.\nХеш пароля генерируется через htpasswd (пакет apache2-utils, который ставили ещё в части 1):\nhtpasswd -nB admin Флаг -n выводит результат сразу в консоль, не записывая в файл; -B - использовать bcrypt. Отдельно подчеркну: не используйте openssl passwd -1 - это устаревший MD5-based хеш, который слабее криптографически и не рекомендуется для новых конфигураций.\nMiddleware:\nhttp: middlewares: auth: basicAuth: users: - \u0026#34;admin:$2y$05$...\u0026#34; # хеш из htpasswd -nB realm: \u0026#34;Restricted\u0026#34; Роутер для dashboard подключает этот middleware и указывает специальный зарезервированный сервис api@internal - под этим именем сам Traefik публикует собственный dashboard и API, отдельного блока services: для него заводить не нужно:\nhttp: routers: dashboard: entryPoints: - websecure rule: \u0026#34;Host(`traefik.domain.ru`)\u0026#34; service: api@internal middlewares: - auth tls: {} tls: {} без явного certResolver - раз уже настроен wildcard-сертификат через defaultGeneratedCert (см. раздел про TLS выше), поддомен dashboard попадает под него автоматически, отдельно прописывать резолвер не нужно.\nРотация логов # Отдельный и очень важный момент, связанный с логами, а вернее с их размером: параметры maxSize/maxBackups/maxAge/compress в static config относятся только к log: (сам traefik.log). Для accessLog: встроенной ротации не существует вообще - Traefik умеет только переоткрыть файл по сигналу USR1, ротацией должен заниматься внешний logrotate.\nПоэтому, чтобы избежать разрастания access.log до сотен мегабайт, я сделал следующее:\nnano /etc/logrotate.d/traefik-access # /etc/logrotate.d/traefik-access # Правила автоматической ротации access.log Traefik. /var/log/traefik/access.log { daily # Проверять необходимость ротации ежедневно. size 20M # Выполнить ротацию, если размер файла достиг 20 МБ. # При использовании вместе с daily ротация произойдёт, # когда выполнится хотя бы одно из условий # (прошёл день или превышен размер). rotate 14 # Хранить 14 архивов логов, затем удалять самые старые. compress # Архивировать старые логи с помощью gzip. delaycompress # Самый свежий архив не сжимать до следующей ротации. # Полезно, если приложение ещё некоторое время # может держать файл открытым. missingok # Не считать ошибкой отсутствие файла логов. notifempty # Не выполнять ротацию, если файл пустой. postrotate # Команды, выполняемые после завершения ротации. systemctl kill -s USR1 traefik.service # Отправить Traefik сигнал USR1. # Traefik закроет старый файл журнала и # откроет новый без перезапуска сервиса. endscript # Конец блока postrotate. } traefik.log при этом продолжает ротироваться встроенным механизмом из static config - два независимых механизма для двух разных файлов, каждый под свою задачу.\nСтруктура dynamic config # Раскладка по каталогам:\n/etc/traefik/dynamic/ ├── middlewares/ │ ├── auth.yaml │ ├── authentik-forwardauth.yaml │ ├── default-headers.yaml │ ├── https-redirect.yaml │ ├── ipAllowList.yaml │ ├── middlewares-buffering.yaml │ ├── nextcloud-secure-headers.yaml │ ├── onlyoffice-middleware.yaml │ ├── rate-limit.yaml │ ├── secure-headers.yaml │ └── ... (библиотека остальных middleware Traefik про запас) ├── services/ │ ├── dashboard.yaml │ ├── nextcloud.yaml │ ├── onlyoffice.yaml │ ├── authentik.yaml │ ├── homepage.yaml │ ├── plex.yaml │ ├── jellyfin.yaml │ └── ... (по одному файлу на сервис) ├── serverstransports.yaml └── tls.yaml Один файл - один сервис или один middleware. Наименование файла сразу говорит, что внутри - не нужно открывать, чтобы понять назначение. Ко всему прочему, если всё описывать в одном файле, получится огромный по объёму YAML, и воспринимать информацию будет очень сложно.\nСоответственно для создания middleware для базовой аутентификации, указанной выше, создаем командой\nnano /etc/traefik/dynamic/middlewares/auth.yaml Динамическую конфигурацию для dashboard создаем командой\nnano /etc/traefik/dynamic/services/dashboard.yaml Библиотека middleware про запас # Помимо тех, что реально используются, завёл файлы для всех middleware из официального списка Traefik OSS, которых ещё не было в структуре: AddPrefix, Chain, CircuitBreaker, Compress, ContentType, DigestAuth, Errors, GrpcWeb, InFlightReq, PassTLSClientCert, ReplacePath(Regex), Retry, StripPrefix(Regex). Не все подключены к реальным роутерам - часть лежит как готовый шаблон на случай, если понадобится (например, InFlightReq пригодится для Jellyfin/Immich при транскодировании, IPAllowList - если когда-нибудь понадобится ограничить доступ к части сервисов по IP). Но у меня на сайте еще будет отдельная статья, посвященная механизму middlewares в Traefik.\nПеренос сервисов с Docker labels на file provider # Больше десятка сервисов (OnlyOffice, Authentik, Audiobookshelf, Dozzle, Forgejo, Komodo, Gotify, Linkwarden, Mealie, Navidrome, весь *arr-стек, Portainer, Trilium, Uptime Kuma, TubeArchivist) до этого маршрутизировались напрямую через Docker labels на самих контейнерах. При переносе в file provider аудит каждого конфига по пути показал несколько вещей, которые стоит упомянуть отдельно - часть из них годами работала незаметно именно потому, что Docker резолвит container name как DNS сам.\nDocker labels - не все они складываются, а перезаписываются # Самая неочевидная находка аудита: если один и тот же лейбл (например, traefik.http.routers.X.middlewares) объявлен на контейнере несколько раз с разными значениями - Traefik использует последнее объявление, предыдущие тихо отбрасываются. У одного из моих сервисов (а точнее у OnlyOffice) таких дублей было три подряд - реально применялось только последнее, а два предыдущих просто ни на что не влияли, никак не сигнализируя об этом, и я жил в неведении.\nDocker DNS-имена не резолвятся вне Docker-сети # Очевидная на бумаге вещь, но про которую очень легко забыть: адреса вида http://authentik_server:9000 или crowdsec:8080 работают только внутри одной и той же Docker-сети. При переезде Traefik в LXC все такие адреса пришлось заменить на реальные IP Docker-хоста - включая переменные окружения самих приложений (например, TRUSTEDREVERSEPROXY/whitelist-параметры у Trilium и Navidrome, которые доверяют заголовкам от конкретной подсети).\nOIDC-клиент vs forwardAuth - не путать # В стеке оказалось два разных паттерна аутентификации через Authentik, и важно не смешивать их:\nforwardAuth middleware на Traefik - нужен приложениям, которые сами не умеют в OIDC (Dozzle, Navidrome, весь *arr-стек, Uptime Kuma). Traefik перехватывает запрос до приложения и проверяет сессию через Authentik. Встроенный OIDC-клиент в самом приложении - Gotify, Mealie, Trilium, Vaultwarden, Komodo умеют говорить с Authentik напрямую как Identity Provider. Здесь authentik@file middleware на Traefik не нужен и был бы избыточен - приложение уже требует логин само. Финальный systemd-юнит # В принципе начальная настройка обратного прокси завершена. Однако осталось сделать ещё одну вещь - превратить наш обратный прокси в полноценный сервис, чтобы можно было использовать обычные команды systemctl.\nnano /etc/systemd/system/traefik.service # /etc/systemd/system/traefik.service # systemd unit для запуска Traefik как системного сервиса. [Unit] Description=Traefik Reverse Proxy # Краткое описание сервиса, отображается в systemctl status. Documentation=https://doc.traefik.io # Ссылка на официальную документацию Traefik. After=network-online.target # Запускать Traefik только после того, как сеть будет полностью поднята. # Это особенно важно при использовании DNS Challenge и удалённых backend. Wants=network-online.target # При запуске Traefik также попытаться активировать network-online.target. # В отличие от Requires, не считается ошибкой, если цель не будет достигнута. [Service] Type=simple # Traefik работает как обычный процесс на переднем плане. # systemd считает сервис запущенным сразу после старта процесса. EnvironmentFile=/etc/traefik/traefik.env # Загружает переменные окружения из файла. # Обычно здесь хранятся секреты, например токен Cloudflare, # чтобы не размещать их в конфигурации Traefik. ExecStart=/usr/local/bin/traefik --configfile=/etc/traefik/traefik.yaml # Команда запуска Traefik. # В качестве конфигурации используется файл traefik.yaml. Restart=on-failure # Автоматически перезапускать сервис, # если он завершился с ошибкой. RestartSec=5 # Перед повторным запуском подождать 5 секунд. # Это предотвращает бесконечный цикл мгновенных перезапусков. [Install] WantedBy=multi-user.target # Запускать сервис автоматически при загрузке системы # после достижения стандартного многопользовательского режима. Работает от root (осознанный выбор для этого homelab) - поэтому AmbientCapabilities=CAP_NET_BIND_SERVICE не нужна, но если решите перейти на непривилегированного пользователя, это первое, что нужно будет добавить вместе с User=/Group=.\nsystemctl daemon-reload systemctl enable --now traefik.service Теперь доступны обычные команды:\nsystemctl status traefik # статус юнита systemctl restart traefik # перезапуск после правки static config systemctl stop traefik # остановка Что осталось сделать в будущем. # Сознательно оставил на отдельный заход, не в рамках этой статьи:\nУстановка и настройка CrowdSec рядом с Traefik. По плану - через apt, локальный LAPI на 127.0.0.1:8080, acquis.yaml читает access.log напрямую с диска, новый bouncer-ключ вместо старого (тот, что раньше лежал в открытом виде в Docker-конфиге, уже отозван). Пока не установлен - соответствующий middleware в entrypoints static config закомментирован. Проброс портов бэкендов на Docker-хосте - сейчас часть сервисов (OnlyOffice, Authentik и другие) недоступны из нового Traefik-сегмента, порты нужно опубликовать на конкретном IP хоста и разрешить точечно через firewall-правила между сегментами сети. Разрешение конфликта портов - Portainer и Authentik оба целятся на 9000 при проксировании, нужно развести. Переключение реальных доменов со старого Docker-based Traefik на новый - пакетами, с проверкой каждого сервиса, а не разом. Как только это будет сделано и новый Traefik примет боевой трафик - старый Docker-контейнер можно будет выключить. Об этом, вероятно, будет отдельная третья часть.\nСсылки # Официальная документация Traefik CrowdSec Список middleware Traefik ","date":"6 August 2026","externalUrl":null,"permalink":"/posts/traefik-in-lxc-part-2/","section":"Posts","summary":"Продолжение серии про Traefik в LXC - от тестового бинарника к рабочей конфигурации. Токен Cloudflare, финальный static config, wildcard-сертификат, защита dashboard через Basic Auth, ротация логов, структура dynamic config и перенос десятка сервисов с Docker labels на file provider. CrowdSec - в планах, отдельным заходом.","title":"Установка Traefik в LXC-контейнер Proxmox как systemd-сервиса | Часть 2","type":"posts"},{"content":" Introduction # Traefik is a modern reverse proxy and load balancer, ideally suited for self-hosting and DevOps setups. In this article we\u0026rsquo;ll walk step by step through how to install Traefik in a Proxmox LXC container and run it as a systemd service, which gives you high reliability and integration with system initialization. For convenience, I\u0026rsquo;ve split the description of this fairly non-trivial process into two parts. This article covers preparation and initial testing of our reverse proxy\u0026rsquo;s functionality.\nNote If you enjoyed this article, you can support me by becoming a sponsor on Boosty (link in the contacts section).\nAdvantages of installing Traefik as a systemd unit # ✅ Starts automatically when the container boots ✅ Managed as a full-fledged service (systemctl start/stop/status) ✅ Runs reliably without Docker ✅ Simple integration with other services Requirements # Before you begin, make sure you have:\n✅ An unprivileged (forget about privileged containers - in this specific case they\u0026rsquo;re a nightmare) LXC container on Proxmox ✅ Debian/Ubuntu inside the container, though it\u0026rsquo;s strongly preferable to use Debian. Never mind that its packages are older - what matters here is stability. ✅ SSH or console access. ✅ An external FQDN domain and a configured DNS server that clearly points all *.domain.ru requests to the IP of your container where Traefik is installed. Step 1: Creating the LXC container # In Proxmox, create an unprivileged container:\nOS: Debian 12 or 13 (recommended) Type: Unprivileged (supported by Traefik) - this parameter is chosen at container creation time (the \u0026ldquo;Unprivileged container\u0026rdquo; checkbox in the Proxmox wizard); if the container was already created as privileged, it\u0026rsquo;s easier to recreate it as unprivileged than to change this parameter after the fact Network: Bridge (e.g., vmbr0) Nesting isn\u0026rsquo;t needed for this scenario - it\u0026rsquo;s only required if you plan to run nested containers inside the LXC itself (for example, Docker/Podman). For Traefik as a systemd service, Nesting doesn\u0026rsquo;t give you anything except an expanded set of system calls available to the container\u0026rsquo;s processes - meaning it needlessly reduces isolation. Leave Nesting disabled unless you plan on containerization inside this LXC. Note that the LXC container only uses the resources it actually needs, not all of the resources allocated to it. An approximate container configuration\nTemplate: Debian 12 or 13 Disk: 32G CPU: 2 Memory: 2048 Swap: 0 Network: static IPv4: 192.168.x.x/24\nBe sure to do the following:\nSet the date and time. This matters. We\u0026rsquo;re going to be looking at this container\u0026rsquo;s logs, so we need the events to reflect the correct time. Moreover, we\u0026rsquo;ll later install crowdsec, which makes a correct timezone doubly important. After all, the time of an attack needs to be recorded precisely. Let\u0026rsquo;s check the time settings\ntimedatectl Find out the correct name of your timezone:\ntimedatectl list-timezones Set your timezone following my example:\ntimedatectl set-timezone Europe/Moscow Let\u0026rsquo;s update the container, or rather the operating system apt full-upgrade Let\u0026rsquo;s install the necessary dependencies. The list below is fairly loose, add whatever else you think is necessary. apt install curl tar sudo lshw apt-transport-https wget nano gnupg htop lsb-release apache2-utils Step 2: Setting up SSH-key-only access # After installing Debian 13, it\u0026rsquo;s recommended to disable password authentication and use only SSH keys. This significantly increases server security and protects against automated password-guessing attempts.\nInstalling the public key # Copy your public key to the server:\nssh-copy-id root@\u0026lt;SERVER_IP\u0026gt; Or manually add the contents of ~/.ssh/id_ed25519.pub to the file: /root/.ssh/authorized_keys\nVerify that key-based login works before moving on to the next step.\nDisabling password login # Open the OpenSSH configuration file:\nnano /etc/ssh/sshd_config Change or add the following parameters:\nPubkeyAuthentication yes PasswordAuthentication no KbdInteractiveAuthentication no PermitRootLogin prohibit-password Where:\nPubkeyAuthentication yes - allows login via SSH keys. PasswordAuthentication no - completely disables password login. KbdInteractiveAuthentication no - disables interactive authentication. PermitRootLogin prohibit-password - allows the root user to log in only via an SSH key. Applying the settings # Before restarting the service, it\u0026rsquo;s recommended to validate the configuration:\nsshd -t If there are no errors, restart the service:\nsystemctl restart ssh Debian 13 specifics # On minimal Debian 13 installs (for example, in Proxmox LXC containers), you might run into this error:\nMissing privilege separation directory: /run/sshd This means the temporary /run/sshd directory, which OpenSSH needs, wasn\u0026rsquo;t automatically created. This can be fixed with a standard command:\nsystemd-tmpfiles --create After that, run the validation check again:\nsshd -t and restart the service:\nsystemctl restart ssh Note The systemd-tmpfiles --create command doesn\u0026rsquo;t change the system configuration or reduce security. It only creates the temporary directories and files described in the systemd-tmpfiles rules, including /run/sshd, which OpenSSH needs to work correctly.\nVerification # Without closing the current SSH session, open a new connection and make sure key-based login works successfully. You can check which parameters took effect with the command:\nsshd -T | grep -E \u0026#39;passwordauthentication|permitrootlogin|pubkeyauthentication|kbdinteractiveauthentication\u0026#39; Expected result:\npasswordauthentication no pubkeyauthentication yes permitrootlogin prohibit-password kbdinteractiveauthentication no Only close the current SSH session after this check succeeds.\nStep 3: Installing the Traefik binary and a first test run # Go to the traefik GitHub repository.\n# download the archive with the latest version of the reverse proxy wget https://github.com/traefik/traefik/releases/download/v3.7.10/traefik_v3.7.10_linux_amd64.tar.gz # extract the archive tar -zxvf traefik_v3.7.10_linux_amd64.tar.gz # move the binary to where it belongs, alongside all the other binaries mv traefik /usr/local/bin/ Now you can delete the unneeded archive to avoid clutter.\nStep 4: Creating the intended management structure for Traefik - namely, the place where we\u0026rsquo;ll store the static config, dynamic config, and logs # All of our reverse proxy\u0026rsquo;s configuration consists of YAML files that define the static and dynamic configuration (yours might differ - or rather, the file locations might differ - the main thing is that the paths are configured correctly)\nmkdir /etc/traefik we\u0026rsquo;ll have one static configuration file mkdir /etc/traefik/dynamic all of our dynamic configuration files will be stored in the corresponding directory. You could of course use a single dynamic configuration file, but it would end up being at least 100 lines long (in reality more), and that much content in one file becomes fairly hard to work with over time. touch /etc/traefik/acme.json create the file that will store our certificate data chmod 600 /etc/traefik/acme.json set the required permissions on the acme.json file. Otherwise, Traefik simply won\u0026rsquo;t start. I think having this kind of safeguard against foolishness is a big plus. We also create the directory where we\u0026rsquo;ll store the logs, namely: traefik.log and access.log\nmkdir -p /var/log/traefik chown root:root /var/log/traefik We\u0026rsquo;ll set up log handling later.\nStep 5: Running the test configuration # At this stage, we create a test Traefik configuration that we need purely to verify that the reverse proxy itself works. We\u0026rsquo;ll expand and refine everything further down the road.\nnano /etc/traefik/traefik.yaml # This is a simple static config. Once again, everything here runs natively, no Docker involved. # Consider enabling the option to send anonymous usage statistics, since it helps the developers. # The DEBUG logging level will show you all debug messages in the console while Traefik is running. # Any yaml file placed in the `/etc/traefik/dynamic` directory is processed in real time, meaning it lets you change the routing, service, middleware, TLS, and server transport configuration \u0026#34;on the fly\u0026#34;. This means we won\u0026#39;t need to restart the service every time. # We\u0026#39;re specifying simple, still unsecured entry points web and websecure. # We allow insecure (since we haven\u0026#39;t issued certificates yet) access to the Traefik panel and API access. # Since yaml format is sensitive to whitespace, if you have an extra space/indent somewhere in the file, the service simply won\u0026#39;t start, but the logs should show you which line the error is on. Note that the line number reported may be inaccurate, so it\u0026#39;s still worth staying vigilant. # https://doc.traefik.io/traefik/contributing/data-collection/ global: checkNewVersion: true sendAnonymousUsage: true # https://doc.traefik.io/traefik/operations/api/ api: dashboard: true insecure: true debug: true disableDashboardAd: false # https://doc.traefik.io/traefik/observability/logs/ log: level: DEBUG #TRACE DEBUG INFO WARN ERROR FATAL PANIC # https://doc.traefik.io/traefik/routing/entrypoints/ entryPoints: web: address: \u0026#34;:80\u0026#34; websecure: address: \u0026#34;:443\u0026#34; #------------: https://doc.traefik.io/traefik/providers/file/ providers: file: directory: /etc/traefik/dynamic watch: true ⚠️ This configuration is temporary and not safe for production. api.insecure: true opens the dashboard and API without any authentication on all of the container\u0026rsquo;s interfaces, and log.level: DEBUG writes excessively verbose logs. Only use this config to check functionality within a closed network segment. If you stop at this step and don\u0026rsquo;t move straight on to part 2 - be sure to set api.insecure back to false (or remove it entirely) and protect the dashboard with a separate authenticated router before exposing the ports to the outside. Checking functionality # Let\u0026rsquo;s run the unexpected traefik command - to start our reverse proxy and verify that everything\u0026rsquo;s fine at this stage: the proxy is running and we can access the Traefik web panel.\nNavigate to the IP address of our reverse proxy, which is available by default on port 8080\nhttp://192.168.0.11:8080/dashboard/\nIf everything went according to plan and it\u0026rsquo;s all working, we\u0026rsquo;ve now built the foundation for further work with the reverse proxy.\nStep 6: Updating Traefik # You might ask me how to update Traefik if it\u0026rsquo;s installed as a binary package. Good question. In fact it\u0026rsquo;s very simple - we\u0026rsquo;ll basically repeat the steps from point 2 of this guide.\nGo to the Traefik GitHub page and find the latest release\nDownload the file you need with the command\nwget https://github.com/traefik/traefik/releases/download/v3.*.*/traefik_v3.*.*_linux_amd64.tar.gz Extract it tar -zxvf traefik_v3.*.*_linux_amd64.tar.gz Move the file to where all the binaries live mv ./traefik /usr/local/bin In the next part, we\u0026rsquo;ll cover setting up a fully working instance of our reverse proxy.\nLinks # Official Traefik documentation Traefik website ","date":"August 5, 2026","externalUrl":null,"permalink":"/en/posts/traefik-in-lxc-part-1/","section":"Posts","summary":"A detailed guide to installing and configuring Traefik in an LXC container to set up a reverse proxy. Covers Docker setup, routing configuration, SSL integration, and recommendations for managing web traffic.","title":"Installing Traefik in a Proxmox LXC container as a systemd service | Part 1","type":"posts"},{"content":" Каждый, кто хоть раз переезжал между системами для заметок, знает это чувство: неделю всё работает через пень-колоду, все бесит, постоянно путаешься. Потом привыкаешь, а через полгода уже и не представляешь, что раньше могло быть как-то иначе.\nЯ использую Obsidian не только для статей на этом сайте. В одном хранилище уживаются заметки по homelab, личная библиотека книг с сотней (будет больше тысячи) карточек, рабочая база для повседневной работы и обычный Zettelkasten для идей, которые жалко потерять. Именно поэтому выбор инструмента и его настройка - это не просто «какой редактор удобнее», а вопрос архитектуры, которая должна выдержать разнородную нагрузку. В моем случае она очень разнородная.\nМои плагины Obsidian # После перехода с Trilium Notes на Obsidian мне пришлось заново собрать привычную рабочую среду. В отличие от Trilium, Obsidian придерживается модульной философии: ядро остается максимально минималистичным, а необходимая функциональность добавляется с помощью плагинов.\nПричиной моего перехода стал не недостаток возможностей Trilium. Наоборот, Trilium Notes 0.104.1 (актуальная версия на дату написания статьи) содержит огромное количество функций уже «из коробки». В версии 0.103.0 появилась возможность писать статьи в markdown. Но мне была необходима полноценная поддержка Front Matter. Благодаря ему заметки становятся обычными Markdown-файлами с метаданными, которые понимает статический генератор сайтов Hugo или Astro. Без front matter мне приходилось делать много тупой однообразной и ручной работы.\nСегодня мое хранилище представляет собой гибрид двух методик:\nPARA - для организации проектов, статей и рабочих материалов. Zettelkasten - для хранения и связывания базы знаний. Я достаточно много времени потратил на выстраивание философии архитектуры своей БД знаний, и в моем случае мне подошел именно гибрид двух указанных выше, широко известных в узких кругах, методик. В их изначальном виде они мне не подходили, их использование только вносило путаницу, простым языком - неимоверно бесили.\nЕсли совсем просто, логика такая:\n00-Inbox - сюда падает всё новое, без раздумий о том, куда это на самом деле относится. Разбираю раз в несколько дней (в лучшем случае). Projects - то, что имеет конкретный результат (в отличии от оригинальной задумки создателя PARA метода, дедлайны меня не волнуют): статья для сайта, разовая задача/проект по работе и т.д. Areas - области интересов, хобби и все, что не имеет каких-то границ и пределов, которые поддерживаются постоянно. У меня это homelab, работа и хобби (у меня их больше одного). Resources - справочные материалы, не привязанные к конкретному проекту: конфиги для homelab, разная документация, каталог бумажной книжной библиотеки, каталог виниловых пластинок. Archive - то, что завершено или не понадобилось (прям вот точно не нужно), но жалко удалять. Разделение на Areas и Resources - пожалуй, главное, ради чего вообще стоило городить гибрид. Чистый Zettelkasten хорош для связывания идей (Наверно хорош. Я не очень уверен, что этот метод подходит кому-то кроме его создателя или какой-нибудь Дарьи Донцовой с ее литературными \u0026ldquo;неграми\u0026rdquo;), но плохо подходит, когда нужно быстро найти «а что у меня по конкретной задаче прямо сейчас». Чистый PARA, наоборот, отлично организует активные дела, но плохо связывает разрозненные заметки между собой. Гибрид берёт от каждой методики то, что реально подошло мне и отбрасывает все остальное.\nЧтобы построить такую систему в Obsidian, я использую следующие плагины.\nБаза данных и метаданные # Dataview # Dataview превращает обычный набор Markdown-файлов в полноценную базу данных. Он умеет строить таблицы, списки, отчеты и выборки на основании полей Front Matter. Плагин в настоящий момент практически не используется в связи с наличием bases как core плагина, но я не удаляю плагин (он просто отключен), так как у него есть функционал, которого нет в bases, да и вроде его разработчик хочет его сильно улучшить в будущем.\nMeta Bind # Позволяет превратить значения Front Matter в интерактивные элементы интерфейса.\nНапример:\nпереключатели; выпадающие списки; поля ввода; кнопки. Это позволяет редактировать свойства заметок без необходимости вручную изменять YAML. В принципе наличие этого плагина скорее блажь. Поигрался и бросил. Мне он в работе не нужен.\nАвтоматизация # Templater # Один из самых мощных плагинов Obsidian.\nИспользуется для создания и автоматизации работы с шаблонами. Позволяет автоматически:\nсоздавать новые заметки; заполнять Front Matter; вставлять текущую дату; выполнять JavaScript-код; формировать сложные шаблоны. QuickAdd # Используется для автоматизации повторяющихся действий. Позволяет создавать собственные команды, которые за одно действие могут:\nсоздать новую заметку; выбрать шаблон; запросить необходимые параметры; автоматически заполнить метаданные. Auto Link Title # Автоматически получает заголовок веб-страницы и вставляет его в Markdown-ссылку.\nВместо\nhttps://example.com получается\n[Название страницы](https://example.com) Paste URL into Selection # Позволяет вставить URL поверх выделенного текста и сразу получить готовую markdown-ссылку, без необходимости вручную оборачивать её в скобки. Просто и незаметно, но экономит секунды на каждой вставленной ссылке.\nLinter # Автоматически приводит заметки к единому стилю.\nНапример:\nсортирует Front Matter; исправляет форматирование; удаляет лишние пробелы; приводит списки к единому виду; стандартизирует оформление Markdown. Obsidian Git # Obsidian Git - плагин для автоматизации работы с Git непосредственно из Obsidian. Он позволяет автоматически коммитить изменения в хранилище и отправлять их в удалённый Git-репозиторий.\nВ моей схеме Obsidian Git используется как первый этап автоматической публикации материалов:\nObsidian → Obsidian Git → Forgejo → автоматизация публикации → сайт ProHomeLab\nЯ редактирую статьи непосредственно в Obsidian, после чего плагин автоматически создаёт Git-коммит и отправляет изменения в приватный репозиторий Forgejo. Дальше Forgejo запускает настроенный workflow, который передаёт изменения в репозиторий сайта и инициирует его сборку и публикацию.\nТаким образом, Git остаётся промежуточным слоем между редактором и сайтом: он одновременно обеспечивает версионирование контента, резервную копию изменений и автоматическую доставку опубликованных материалов.\nОрганизация хранилища # Folder Notes # Позволяет каждой папке иметь собственную заметку. Фактически папка становится полноценным разделом документации со своей главной страницей. В связи с использованием Notebook Navigator (который имеет идентичный, но встроенный функционал), в настоящий момент не используется. Я использую эту функцию, как возможность встроить некую бд в корневых папках, суть которой индексировать содержимое таких папок.\nNotebook Navigator # Значительно улучшает навигацию по Vault. Фактически это кастомизация работы с проводником в Obsidian. Разница примерно как между ванильным Gnome и KDE Plasma. Делает работу с большим количеством заметок намного удобнее (но дело вкуса).\nHomepage # Автоматически открывает выбранную заметку при запуске Obsidian. Несмотря на наличие у меня заметки, которая может выступать в качестве dashboard, я им не пользуюсь.\nIcon Folder # Позволяет назначать папкам собственные иконки. Считается, что это делает дерево заметок значительно более наглядным, но в моем случае это опять же как игрушка, которая есть, но в нее не играешь.\nFile Explorer Note Count # Показывает количество заметок внутри каждой папки. Очень удобно для контроля структуры большого Vault.\nПоиск и навигация # Omnisearch # Полностью заменяет стандартный поиск Obsidian. Работает значительно быстрее и предоставляет более удобные результаты поиска. Особенно заметно это становится при работе с большим количеством заметок.\nCommander # Позволяет создавать собственные команды и добавлять их в интерфейс Obsidian. Используется для ускорения часто выполняемых действий путем их выноса на видное место. По факту - экономит клики мышью.\nQuick Switcher ++ # Расширяет возможности стандартного Quick Switcher. Поиск и переход между заметками становятся заметно удобнее.\nПланирование # Calendar # Добавляет календарь. Используется для ежедневных заметок и навигации по ним. Но я им не пользуюсь. В Notebook Navigator есть свой, более продвинутый календарь, которым я \u0026hellip;. тоже не пользуюсь.\nTasks # Значительно расширяет работу с задачами. Поддерживает:\nсроки выполнения; повторяющиеся задачи; фильтрацию; запросы Dataview; отчеты по задачам. Reminder # Добавляет систему напоминаний. Позволяет получать уведомления о важных задачах и событиях.\nKanban # Добавляет полноценные Kanban-доски непосредственно в Obsidian. Позволяет вести проекты без использования сторонних сервисов.\nРабота с текстом # Better Word Count # Отображает расширенную статистику документа:\nколичество слов; количество символов; предложения; абзацы. Особенно полезен при написании статей.\nReading Time # Автоматически рассчитывает предполагаемое время чтения статьи. Использую его при подготовке материалов для сайта. Но опять же - это скорее украшательство, чем практическая польза в моем случае.\nEditing Toolbar # Добавляет визуальную панель инструментов редактора Markdown. Работаешь как в обычном офисном пакете. Особенно полезна тем, кто не помнит или не хочет запоминать все сочетания клавиш markdown.\nAdvanced Tables # Делает работу с Markdown-таблицами максимально удобной. Фактически превращает их в небольшой аналог электронных таблиц. Ну и не надо руками набивать вертикальные и горизонтальные черточки.\nРабота с изображениями и мультимедиа # Local Images Plus # Автоматически скачивает изображения из Интернета и сохраняет их локально.\nБлагодаря этому все заметки становятся полностью автономными в том числе и картинки, но требуется дополнительная настройка. Плагин надо использовать острожно, иначе он может захламить всю систему.\nImage Toolkit # Расширяет возможности просмотра изображений. Позволяет масштабировать их и работать с ними становится значительно удобнее.\nMedia Extended # Добавляет расширенную поддержку видео и аудио непосредственно внутри заметок. Можешь вставлять ссылки из ютуба, ну или чем ты там пользуешься, прямо в заметки и просматривать их оттуда же.\nMaps # Позволяет вставлять интерактивные карты. Полезен для заметок, связанных с путешествиями и географией. Не использую, но установлен.\nExcalidraw # Добавляет полноценную доску для рисования.\nИспользуется для создания:\nсхем; диаграмм; интеллект-карт; архитектуры сервисов. Для технической документации практически незаменим. На самом деле и не только для технической документации крайне удобен, но зависит от твоих потребностей.\nZim Reader # Позволяет открывать файлы формата ZIM прямо внутри Obsidian. Например, локальную копию Википедии. У меня как раз для Wikipedia и используется.\nЭкспорт и оформление # Better Export PDF # Значительно улучшает экспорт заметок в PDF. Получаемые документы выглядят гораздо профессиональнее.\nAdmonition # Добавляет красивые информационные блоки Callout:\nNote; Tip; Warning; Danger; Success; Info. В принципе простое украшательство на которое лично мне плевать.\nCode Styler # Улучшает оформление блоков кода. Особенно полезен при написании технических статей. Obsidian любит портить разметку кода, когда все съезжает и потом замучаешься удалять пробелы и т.д.\nВнешний вид # Minimal # Основная тема оформления моего хранилища. Минималистичная, аккуратная и очень хорошо настраивается.\nStyle Settings # Позволяет настраивать темы и плагины через удобный графический интерфейс. Многие современные темы используют именно этот плагин, но я им практически не пользовался.\nMinimal Settings # Добавляет дополнительные настройки специально для темы Minimal. Один раз настроил и потом он просто висит в фоне.\nОбслуживание # Plugin Update Tracker # Следит за обновлениями установленных плагинов.\nПозволяет быстро узнать о выходе новых версий плагинов, но в России могут быть проблемы, так как ему нужен доступ к серверам AWS.\nBRAT # Позволяет устанавливать тестовые версии плагинов напрямую из GitHub. Используется в тех случаях, когда нужная возможность еще не попала в официальный релиз.\nСинхронизация # Remotely Save # Использую для синхронизации хранилища с Nextcloud.\nПозволяет не использовать платный Obsidian Sync и самостоятельно выбирать место хранения данных. Плюс не нужна внешняя БД или жрущий батарейку смартфона Syncthing.\nЧто из этого есть в Trilium Notes? # Интересно, что большая часть перечисленных выше возможностей уже присутствует в Trilium Notes 0.104 без установки каких-либо дополнительных расширений.\nИз коробки доступны:\nработа с шаблонами; система атрибутов заметок; мощный поиск; задачи; напоминания; календарь; Kanban-представления; таблицы; встроенный редактор диаграмм; интерактивные карты; экспорт документов; информационные блоки; расширенный редактор; навигация по дереву заметок; автоматизация с помощью JavaScript. Именно поэтому после перехода с Trilium может показаться, что в Obsidian приходится устанавливать десятки плагинов (в моем случае больше трех десятков), чтобы вернуть привычную функциональность.\nОднако философия этих программ различается.\nTrilium предлагает максимально насыщенную функциональность сразу после установки.\nObsidian предоставляет минималистичное ядро, позволяя пользователю самостоятельно собрать рабочую среду под свои задачи.\nИменно возможность использовать обычные Markdown-файлы с Front Matter, интеграция с Bases, Git и другими инструментами стали для меня главной причиной перехода на Obsidian, несмотря на необходимость установки большого количества плагинов.\nСравнительная таблица плагинов Obsidian и встроенных функций Trilium # | Возможность | Obsidian | Trilium Notes 0.104 |\n| \u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash; | \u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash; | \u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026mdash;\u0026ndash; |\n| Календарь | Calendar | Встроено |\n| Задачи | Tasks | Встроено |\n| Канбан | Kanban | Встроено |\n| Шаблоны | Templater | Встроено |\n| Атрибуты заметок | Meta Bind + Front Matter | Встроено |\n| Карты | Maps | Встроено |\n| Диаграммы | Excalidraw | Встроено (диаграммы и canvas) |\n| Таблицы | Table Editor | Встроено |\n| Напоминания | Reminder | Встроено |\n| Поиск | Omnisearch | Встроено |\n| Экспорт PDF | Better Export PDF | Встроено |\n| Иконки папок | Icon Folder | Встроено |\n| Домашняя страница | Homepage | Встроено |\n| Локальные изображения | Local Images Plus | Встроено |\n| Подсчет слов | Better Word Count | Встроено |\n| Время чтения | Reading Time | Встроено |\n| Автооформление | Linter | Встроено |\n|Синхронизация заметок | Remotly Save | Встроено |\nИтоги # Тридцать шесть плагинов звучит пугающе, но по факту большая часть из них - это разовая настройка, о которой я забыл сразу после того, как всё заработало. Основной рабочий контур - это Templater, Notebook Navigator, Bases и Front Matter. Всё остальное - надстройки, часть из которых я включил один раз и больше не трогал (привет, Meta Bind и Maps).\nЕсли бы меня спросили, стоило ли оно того - да, безусловно. Но не потому, что Obsidian функционально богаче Trilium (это не так, из коробки Trilium даёт больше, намного больше), а потому что мне нужен был именно текстовый файл с Front Matter, который понимает Hugo - и вокруг этой одной потребности пришлось строить всё остальное заново.\nКому подойдёт что # Trilium - если тебе не нужно публиковать заметки на статическом сайте, важен self-hosted и максимум функциональности из коробки без танцев бубном в попытке заставить работать все плагины разом и без конфликтов. Мощный инструмент за один вечер (ну может два) настройки.\nObsidian - если, как и мне, нужен именно plain-text Markdown с Front Matter, интеграция с Git и статическими генераторами сайтов, и ты готов потратить время (много времени, очень много времени) на сборку своей экосистемы плагинов под конкретные задачи.\nНи один из вариантов не «лучше» в общем смысле - они выросли из разной философии, и вопрос в том, какая философия ближе твоей задаче.\n","date":"26 July 2026","externalUrl":null,"permalink":"/posts/obsidian-plugins/","section":"Posts","summary":"Разбираю 36 плагинов Obsidian, которые заменили встроенный функционал Trilium Notes после переезда - от Templater и Bases до Excalidraw и Kanban. Сравниваю философию двух систем и объясняю, почему решающим фактором стала поддержка YAML Front Matter для публикации статей через Hugo.","title":"Плагины Obsidian, которыми я пользуюсь","type":"posts"},{"content":"","date":"19 July 2026","externalUrl":null,"permalink":"/tags/nas/","section":"Tags","summary":"","title":"NAS","type":"tags"},{"content":" Автоматические снапшоты ZFS с помощью Sanoid на Fedora Server 44 # Это продолжение предыдущей статьи про создание собственного NAS на базе Fedora Server 44. В прошлый раз мы установили Fedora Server, подключили ZFS, создали первый датасет и расшарили его по сети с помощью Samba.\nСегодня продолжаем допиливать наш NAS. На этот раз займемся одной из самых крутых фишек ZFS - снапшотами. А чтобы не делать все вручную, сразу автоматизируем этот процесс с помощью утилиты Sanoid.\nЗачем вообще нужны снапшоты? # ZFS - очень мощная и невероятно надежная файловая система. Конечно, без недостатков тоже не обошлось, но преимуществ у нее гораздо больше.\nОдна из главных фишек ZFS - это снапшоты. По сути, это снимок состояния файловой системы в определенный момент времени. Если что-то пошло не так - случайно удалили файлы, неудачно обновили систему или словили программу-вымогатель - можно просто откатиться к предыдущему состоянию, как будто ничего и не произошло.\nКонечно, совсем бесплатно это не работает. Снапшоты занимают место на диске, но только под измененные данные. Пока файлы не меняются, снапшот практически ничего не весит. Поэтому платить приходится только за изменения, а не за полную копию данных.\nВ TrueNAS работа со снапшотами вынесена в удобный WebUI. В Fedora Server такого удобства нет - Cockpit пока не умеет полноценно работать с ZFS.\nНо ничего страшного, мы и тут не пропадем.\nРабота со снапшотами вручную # Для начала давайте посмотрим, как вообще работают снапшоты вручную.\n# Создать снапшот sudo zfs snapshot data/media@before-upgrade # Откатиться к снапшоту sudo zfs rollback data/media@before-upgrade # Проверить целостность пула (желательно выполнять примерно раз в месяц) sudo zpool scrub data Для локальной работы можно включить отображение каталога .zfs:\nsudo zfs set snapdir=visible data/media Однако Samba не отображает этот служебный каталог SMB-клиентам. Если вы хотите пользоваться снапшотами прямо из Проводника Windows через меню «Предыдущие версии», потребуется настроить модуль shadow_copy2. Именно так эта возможность реализована в TrueNAS После этого в каталоге появится скрытая папка .zfs, внутри которой можно просматривать содержимое всех снапшотов. Иногда это оказывается очень удобно, если нужно быстро достать случайно удаленный файл без полного отката файловой системы.\nОднако, несмотря на то что ручной труд облагораживает человека, как и любой другой труд, память у нас штука ненадежная. ИИ-агентами лично я пользоваться не хочу, да и давать им доступ к своим данным - идея довольно смелая. Смелая, но глупая\nПоэтому давайте автоматизируем весь этот процесс с помощью широко известного в узких кругах набора утилит Sanoid.\nSanoid умеет автоматически создавать снапшоты по расписанию, удалять устаревшие и поддерживать заданную политику хранения без какого-либо участия пользователя.\nУстановка Sanoid # Шаг 1. Устанавливаем необходимые зависимости # Для начала установим Git и все библиотеки, которые необходимы для работы Sanoid.\nsudo dnf install -y \\ git \\ perl-Config-IniFiles \\ perl-Data-Dumper \\ perl-Capture-Tiny \\ perl-Getopt-Long \\ lzop \\ mbuffer \\ mhash \\ pv На Fedora все необходимые Perl-модули уже находятся в официальных репозиториях, поэтому дополнительно подключать EPEL или устанавливать пакеты через CPAN не потребуется.\nШаг 2. Загружаем Sanoid # Переходим во временную директорию и клонируем официальный репозиторий проекта.\ncd /tmp sudo git clone https://github.com/jimsalterjrs/sanoid.git cd sanoid Переключимся на последнюю стабильную версию.\nsudo bash -c \u0026#39;cd /tmp/sanoid \u0026amp;\u0026amp; git checkout \u0026#34;$(git tag | grep \u0026#34;^v\u0026#34; | tail -n 1)\u0026#34;\u0026#39; Конечно, можно оставить и ветку master, но лично я предпочитаю использовать стабильные релизы. Домашний NAS - это не то место, где хочется неожиданно словить баг после очередного обновления.\nШаг 3. Устанавливаем программу # Теперь установим сам Sanoid.\nКопируем исполняемые файлы:\nsudo cp sanoid syncoid findoid sleepymutex /usr/local/sbin Создаем каталог для конфигурационных файлов:\nsudo mkdir -p /etc/sanoid Копируем настройки по умолчанию:\nsudo cp sanoid.defaults.conf /etc/sanoid/ Создаем основной файл конфигурации:\nsudo touch /etc/sanoid/sanoid.conf И на всякий случай сохраним пример конфигурации. Он пригодится, если захотите настроить более сложные сценарии.\nsudo cp sanoid.conf /etc/sanoid/sanoid.example.conf На этом установка Sanoid завершена. Осталось научить систему запускать его автоматически.\nНастраиваем автоматический запуск # Поскольку Fedora использует systemd, логично доверить запуск Sanoid именно ему.\nСоздадим два небольших сервиса: один будет отвечать за создание снапшотов, а второй - за удаление устаревших.\nСоздаем сервис создания снапшотов # Создаем файл:\nsudo nano /etc/systemd/system/sanoid.service Вставляем следующее содержимое:\n[Unit] Description=Create ZFS Snapshots Requires=zfs.target After=zfs.target Wants=sanoid-prune.service Before=sanoid-prune.service ConditionFileNotEmpty=/etc/sanoid/sanoid.conf [Service] Type=oneshot Environment=TZ=UTC ExecStart=/usr/local/sbin/sanoid --take-snapshots --verbose Здесь нет ничего сложного. Этот сервис просто запускает Sanoid, который создает снапшоты в соответствии с нашей будущей конфигурацией.\nОбратите внимание на строку:\nConditionFileNotEmpty=/etc/sanoid/sanoid.conf Она запрещает запуск сервиса до тех пор, пока мы не создадим файл конфигурации. Очень полезная мелочь, которая избавляет от лишних ошибок при первой настройке.\nСоздаем сервис очистки снапшотов # Теперь создадим второй сервис.\nsudo nano /etc/systemd/system/sanoid-prune.service И вставляем:\n[Unit] Description=Prune ZFS Snapshots Requires=zfs.target After=zfs.target sanoid.service ConditionFileNotEmpty=/etc/sanoid/sanoid.conf [Service] Type=oneshot Environment=TZ=UTC ExecStart=/usr/local/sbin/sanoid --prune-snapshots --verbose [Install] WantedBy=sanoid.service Этот сервис занимается уборкой: удаляет снапшоты, срок хранения которых уже закончился согласно нашей политике.\nТаким образом нам вообще не придется думать о том, когда чистить старые снимки - Sanoid сделает все сам.\nСоздаем таймер # Осталось научить systemd запускать Sanoid по расписанию.\nСоздаем таймер:\nsudo nano /etc/systemd/system/sanoid.timer И вставляем:\n[Unit] Description=Run Sanoid every 15 minutes Requires=sanoid.service [Timer] OnCalendar=*:0/15 Persistent=true [Install] WantedBy=timers.target В моем случае Sanoid запускается каждые 15 минут.\nДля домашнего NAS этого более чем достаточно. Если ваши данные меняются редко, интервал можно спокойно увеличить, например до одного часа.\nАктивируем сервисы # После того как все сервисы созданы, осталось сообщить о них systemd и включить автоматический запуск.\nДля начала перечитаем конфигурацию:\nsudo systemctl daemon-reload Разрешим запуск сервиса очистки снапшотов:\nsudo systemctl enable sanoid-prune.service И включим таймер:\nsudo systemctl enable --now sanoid.timer Проверить, что таймер успешно запустился, можно командой:\nsystemctl list-timers sanoid.timer Ожидаемый результат будет примерно таким:\nNEXT LEFT LAST Fri 2026-07-17 10:15:00 12 min Fri 2026-07-17 10:00:00 На этом установка полностью завершена.\nПроверяем установку # Для собственного спокойствия можно убедиться, что Sanoid действительно установлен.\nНапример, посмотреть его версию:\nsanoid --version Или открыть встроенную справку:\nsanoid --help Если команды выполняются без ошибок - все прошло успешно.\nНастраиваем расписание снапшотов # На данный момент есть один небольшой нюанс.\nSanoid уже установлен.\nТаймер уже работает.\nSystemd уже каждые 15 минут пытается запускать Sanoid.\nНо… делать он пока ничего не будет.\nВсе потому, что мы еще не рассказали ему, какие датасеты нужно обслуживать и сколько снапшотов необходимо хранить.\nПоэтому открываем основной файл конфигурации:\nsudo nano /etc/sanoid/sanoid.conf По умолчанию Sanoid поставляется с большим количеством готовых шаблонов. Если интересно посмотреть все возможности утилиты, рекомендую заглянуть в официальный пример конфигурации:\nhttps://github.com/jimsalterjrs/sanoid/blob/master/sanoid.conf\nНо для домашнего NAS настолько сложная конфигурация обычно не нужна.\nПредположим, что наш пул называется data, а все пользовательские данные находятся в датасете data/media.\nТогда файл sanoid.conf будет выглядеть следующим образом:\n[data/media] use_template = production [template_production] frequently = 0 hourly = 36 daily = 30 weekly = 4 monthly = 3 yearly = 0 autosnap = yes autoprune = yes Разберемся, что означают эти параметры.\nВ данной конфигурации Sanoid будет автоматически:\nхранить 36 почасовых снапшотов; хранить 30 ежедневных; хранить 4 еженедельных; хранить 3 ежемесячных; не создавать \u0026ldquo;частые\u0026rdquo; (frequently) и годовые (yearly) снапшоты. Параметр\nautosnap = yes включает автоматическое создание снапшотов.\nА параметр\nautoprune = yes автоматически удаляет старые снапшоты, срок хранения которых уже закончился.\nВажно. Вместо data/media укажите имя своего ZFS-датасета. Узнать его можно командой:\nzfs list Если нужно защищать сразу весь пул # Если в вашем пуле несколько датасетов (media, documents, backups, nextcloud и так далее), гораздо удобнее использовать рекурсивную обработку.\nВ этом случае достаточно написать:\n[data] use_template = production recursive = yes [template_production] frequently = 0 hourly = 36 daily = 30 weekly = 4 monthly = 3 yearly = 0 autosnap = yes autoprune = yes Теперь Sanoid будет автоматически обслуживать все дочерние датасеты внутри пула data.\nНа мой взгляд, именно такой вариант является наиболее удобным для домашнего NAS. Не придется каждый раз добавлять новые датасеты в конфигурацию вручную - они сразу попадут под действие политики хранения. Это особенно удобно, если вы часто экспериментируете и создаете новые датасеты.\nПроверяем, что все работает # Давайте еще раз посмотрим, что мы уже сделали.\n✅ Установили Sanoid. ✅ Создали сервис создания снапшотов. ✅ Создали сервис очистки старых снапшотов. ✅ Настроили таймер systemd. ✅ Описали политику хранения снапшотов. Теперь каждые 15 минут systemd будет пытаться запускать Sanoid.\nПосмотреть список всех активных таймеров можно командой:\nsudo systemctl list-timers И здесь есть один важный момент.\nПока файл /etc/sanoid/sanoid.conf пустой, ничего происходить не будет. Именно для этого мы ранее добавили строку:\nConditionFileNotEmpty=/etc/sanoid/sanoid.conf Как только вы сохраните конфигурацию хотя бы с одним датасетом, следующий запуск таймера автоматически начнет создавать снапшоты.\nНикаких дополнительных действий выполнять не нужно. Не нужно перезапускать таймер, перезагружать сервер или заново включать сервисы - systemd сам подхватит новую конфигурацию.\nЕсли не хочется ждать ближайшие 15 минут, можно проверить работу вручную.\nСоздать снапшоты:\nsudo sanoid --take-snapshots --verbose Или запустить сервис, который обычно вызывается таймером:\nsudo systemctl start sanoid.service После этого можно убедиться, что снапшот действительно появился:\nzfs list -t snapshot Если вы увидели новый снапшот - поздравляю, все работает именно так, как и должно.\nА как же резервное копирование? # Здесь очень важно понимать один момент.\nСнапшоты - это не резервные копии.\nДа, они отлично защищают от случайного удаления файлов, неудачных обновлений или действий программ-вымогателей. Но если выйдет из строя сам диск, контроллер или сгорит весь сервер, вместе с ним пропадут и все снапшоты.\nПоэтому снапшоты - это первая линия защиты данных, а не полноценный бэкап.\nSyncoid - следующий шаг # К счастью, разработчики Sanoid подумали и об этом.\nВместе с Sanoid устанавливается еще одна замечательная утилита - Syncoid. Она умеет реплицировать ZFS-датасеты на другой пул, другой сервер или даже в другую географическую точку через SSH.\nСамый простой пример выглядит так:\nsudo syncoid -r data backup где:\ndata - пул или датасет, который мы реплицируем; backup - пул или датасет, куда будут отправляться данные. На первый взгляд команда выглядит очень простой, но под капотом Syncoid делает довольно серьезную работу. Утилита сама определяет, какие данные изменились после предыдущей синхронизации, передает только разницу между снапшотами и автоматически возобновляет передачу, если соединение неожиданно оборвалось.\nИменно поэтому связка Sanoid + Syncoid считается одним из лучших решений для организации резервного копирования на базе ZFS.\nЗаключение # На этом настройку автоматических снапшотов можно считать завершенной.\nТеперь ваш NAS умеет самостоятельно:\nсоздавать снапшоты по расписанию; автоматически удалять устаревшие снимки; поддерживать заданную политику хранения без какого-либо участия пользователя. В следующей статье мы подробно разберем Syncoid и настроим полноценную репликацию данных между двумя ZFS-пулами. После этого наш NAS сможет пережить уже не только случайное удаление файлов, но и выход из строя целого сервера.\n","date":"19 July 2026","externalUrl":null,"permalink":"/posts/fedora-server-sanoid-zfs-snapshots/","section":"Posts","summary":"Продолжение цикла статей про домашний NAS на Fedora Server 44. На этот раз настраиваем автоматическое создание и очистку снапшотов ZFS с помощью Sanoid, разбираем политику хранения снимков и systemd-таймеры, а также знакомимся с Syncoid для будущей репликации данных на резервный сервер.","title":"Автоматические снапшоты ZFS на Fedora Server 44 с помощью Sanoid","type":"posts"},{"content":" Введение # В этой статье мы соберём современный домашний NAS на базе Fedora Server 44, файловой системы OpenZFS и файлового сервера Samba.\nДолгое время я использовал TrueNAS в качестве операционной системы для хранения данных. Это отличная система, однако со временем пришёл к выводу, что в моём случае она избыточна. NAS у меня выполняет одну задачу - хранение файлов, поэтому многие возможности TrueNAS остались невостребованными. При этом всё остальное оказалось интереснее и удобнее настроить самостоятельно..\nВ качестве основы я выбрал Fedora Server. Мы получим полноценную Linux-систему, веб-интерфейс Cockpit, файловую систему ZFS и привычный общий доступ по SMB.\nПочему Fedora Server, а не TrueNAS? # Перед тем как перейти к настройке, хочу ответить на вполне логичный вопрос: почему вообще Fedora Server, если уже используешь TrueNAS, или почему не попробовать любые другие готовые операционные системы для nas?\nНа протяжении долгого времени я использовал TrueNAS в качестве основной операционной системы для домашнего NAS. Это отличное решение с удобным веб-интерфейсом и большим количеством встроенных возможностей. Однако со временем я понял, что использую лишь небольшую часть его функциональности, а некоторые особенности Truenas начали раздражать.\nДля меня NAS - это прежде всего надежное хранилище данных. Все остальные сервисы - Nextcloud, Immich, Jellyfin, Grafana, Docker и другие - работают на отдельных серверах и виртуальных машинах. В результате большинство возможностей TrueNAS оказалось просто невостребованным.\nFedora Server, наоборот, предоставляет чистую и современную Linux-систему без лишних компонентов. Это дает несколько преимуществ:\nполный контроль над операционной системой; всегда актуальные версии программного обеспечения, но без нюансов arch-подобных систем; возможность самостоятельно выбрать необходимые сервисы; удобное администрирование через Cockpit; полноценную поддержку OpenZFS; отсутствие ограничений, характерных для специализированных NAS-дистрибутивов. Согласен, что такой подход требует немного больше времени на первоначальную настройку и наличие знаний чуть выше базовых умений кликать мышкой. Зато в дальнейшем вы получаете максимально гибкую систему, которую легко адаптировать под свои задачи, не завися от особенностей конкретной NAS-платформы.\nИменно поэтому в качестве основы для домашнего файлового сервера я выбрал Fedora Server 44.\nПодготовка Fedora Server # Обновление системы # sudo dnf update -y В современных RPM-дистрибутивах команда dnf update уже включает функциональность прежнего dnf upgrade.\nУстановка необходимых пакетов # sudo dnf install -y \\ tar gzip curl unzip git procps-ng findutils nano \\ cockpit-bridge coreutils attr hostname iproute glibc-common \\ systemd nfs-utils samba samba-client samba-common-tools Дополнительные инструменты # sudo dnf install -y lm_sensors cockpit-sosreport sudo sensors-detect sudo systemctl restart cockpit.socket Установка Cockpit Sensors # sudo wget https://github.com/ocristopfer/cockpit-sensors/releases/latest/download/cockpit-sensors.tar.xz # sudo mkdir -p /usr/share/cockpit/sensors # tar -xf cockpit-sensors.tar.xz cockpit-sensors/dist # sudo cp -r cockpit-sensors/dist/* /usr/share/cockpit/sensors/ # rm -rf cockpit-sensors cockpit-sensors.tar.xz sudo systemctl restart cockpit.socket Установка OpenZFS # Добавляем репозиторий:\nsudo dnf install -y https://zfsonlinux.org/fedora/zfs-release-3-1$(rpm --eval \u0026#34;%{dist}\u0026#34;).noarch.rpm Устанавливаем заголовки текущего ядра:\nsudo dnf install -y kernel-devel-$(uname -r | awk -F\u0026#39;-\u0026#39; \u0026#39;{print $1}\u0026#39;) Устанавливаем OpenZFS:\nsudo dnf install -y zfs Загружаем модуль:\nsudo modprobe zfs # Указываем системе, чтобы модуль загружался при перезагрузке echo zfs | sudo tee /etc/modules-load.d/zfs.conf На всякий случай проверяем, что zfs у нас будет работать после перезагрузки системы:\nsudo reboot Проверяем установку:\nzfs version Создание пула ZFS # Создадим зеркальный пул из двух дисков:\nlsblk # вывод списка дисков sudo zpool create -m /srv data mirror /dev/sda /dev/sdb Важно: не используйте в качестве точки монтирования ZFS каталог /mnt для публикации через Samba. На Fedora Server 44 с OpenZFS 2.4.x Samba может выдавать ошибку \u0026gt; canonicalize_connect_path failed. У меня с директорией /mnt расшаривание по самбе не работало. При использовании /srv все заработало с полпинка.\nWarning В идеале крайне желательно монтировать по id диска, чтобы избежать проблем, когда при перезагрузке буквы дисков съезжают\nsudo zpool create -m /srv data mirror /dev/disk/by-id/ata-XXXX /dev/disk/by-id/ata-YYYYСоздадим датасет:\nsudo zfs create data/media Проверяем, что пул и датасет созданы:\nzpool status zfs list Включим сжатие:\nsudo zfs set compression=lz4 data Назначим владельца:\nsudo chown -R stilicho:stilicho /srv/media Здесь я вставлю небольшую ремарку (прости меня Эрих Мария). На твоем месте я бы перезагрузил систему и проверил бы еще раз, что пул и датасет смонтируются после перезагрузки:\nsudo reboot zpool status zfs list В случае, если после перезагрузки пул не смонтировался, то введи следующие команды:\nsudo systemctl enable zfs-import-cache.service sudo systemctl enable zfs-import-scan.service sudo systemctl enable zfs-mount.service sudo systemctl enable zfs.target Теперь:\nsudo reboot и проверяй результат\nНастройка SELinux # sudo semanage fcontext -a -t samba_share_t \u0026#34;/srv/media(/.*)?\u0026#34; sudo restorecon -Rv /srv/media Эта команда добавляет правило SELinux, которое назначает тип контекста samba_share_t каталогу /srv/media и всему его содержимому. Благодаря этому Samba получает право предоставлять доступ к этому каталогу по сети.\nРазберем команду по частям:\nsudo semanage fcontext -a -t samba_share_t \u0026#34;/srv/media(/.*)?\u0026#34; sudo - выполнить команду с правами администратора. semanage - утилита для управления политиками SELinux. fcontext - управление контекстами файлов. -a - добавить новое правило. -t samba_share_t - назначить тип SELinux samba_share_t, предназначенный для общих папок Samba. \u0026quot;/srv/media(/.*)?\u0026quot; - регулярное выражение: - /srv/media - сам каталог; - (/.*)? - все файлы и подкаталоги внутри него. После добавления правила необходимо применить новый контекст к существующим файлам:\nsudo restorecon -Rv /srv/media restorecon - применяет контексты SELinux в соответствии с правилами. -R - рекурсивно обрабатывает все вложенные каталоги и файлы. -v - выводит информацию обо всех изменениях. Проверка:\nls -Zd /srv/media Ожидаемый результат:\nsystem_u:object_r:samba_share_t:s0 /srv/media Настройка Samba # Создаем отдельного локального пользователя Linux, который будет использоваться для доступа к SMB-шаре.:\nsudo useradd samba # sudo smbpasswd -a samba Зададим права пользователю samba на датасет, который мы будем расшаривать\nsudo groupadd media # создаем отдельную группу для шаринга # добавляем туда наших пользователей sudo usermod -aG media stilicho sudo usermod -aG media samba # задаем права на датасет для пользователей группы media sudo chown -R stilicho:media /srv/media sudo chmod -R 775 /srv/media sudo find /srv/media -type d -exec chmod g+s {} \\; Создаем samba шару Добавьте в /etc/samba/smb.conf:\n[share] comment = Shared Network Folder path = /srv/media browseable = yes read only = no valid users = samba force group = media create mask = 0644 directory mask = 2755 Запускаем службы:\nsudo systemctl enable --now smb nmb sudo systemctl status smb Проверяем:\nsmbclient //localhost/share -U samba Если всё настроено правильно, откроется консоль Samba.\nПодключение из Windows # Откройте проводник и введите:\n\\\\IP-АДРЕС-СЕРВЕРА\\share Введите логин и пароль пользователя Samba.\nСоздайте тестовую папку и файл, затем убедитесь, что они успешно создаются и после перезапуска сервера остаются доступными.\nЗаключение # В результате мы получили полноценный домашний NAS на Fedora Server 44 с файловой системой OpenZFS, веб-интерфейсом Cockpit и файловым сервером Samba. Такой подход обеспечивает полный контроль над системой, хранение данных без привязки к специализированным NAS-дистрибутивам. При этом Fedora остается обычной Linux-системой, которую легко расширить любыми сервисами по мере необходимости, что мы с вами и сделаем в следующих статьях.\n","date":"15 July 2026","externalUrl":null,"permalink":"/posts/fedora-server-nas/","section":"Posts","summary":"Собираем современный домашний NAS на Fedora Server 44 с файловой системой OpenZFS, веб-интерфейсом Cockpit и файловым сервером Samba. Полная пошаговая инструкция по установке, настройке ZFS, SELinux и публикации SMB-шары.","title":"Настройка домашнего NAS на Fedora Server 44 с OpenZFS, Cockpit и Samba","type":"posts"},{"content":"","date":"12 July 2026","externalUrl":null,"permalink":"/series/homelab/","section":"Series","summary":"","title":"Homelab","type":"series"},{"content":"","date":"12 July 2026","externalUrl":null,"permalink":"/categories/nas/","section":"Categories","summary":"","title":"NAS","type":"categories"},{"content":"","date":"12 July 2026","externalUrl":null,"permalink":"/tags/ollama/","section":"Tags","summary":"","title":"Ollama","type":"tags"},{"content":"","date":"12 July 2026","externalUrl":null,"permalink":"/tags/openclaw/","section":"Tags","summary":"","title":"OpenClaw","type":"tags"},{"content":" Вступление # Тем, кто смотрел мои старые ролики, могло показаться, что они слышат в моем голосе сарказм и иронию, когда я упоминаю ИИ.\nНа самом деле вам не показалось. Но моя ирония связана только с тем сумасшествием, которое сопровождает бум ИИ. Полгода назад все сходили с ума по ChatGPT и кричали, что вот оно - будущее.\nПрошло полгода. Теперь все кричат, что будущее - это ИИ-агенты, что всех заменят ИИ-агенты, а сотрудники какой-нибудь NVIDIA должны работать сразу с 50 такими агентами. Что делать с предыдущим будущим - непонятно. Но тут главное, чтобы народ был вечно в изумлении, а то люди начнут задавать вопросы, и самопровозглашенным трендсеттерам они точно не понравятся.\nКороче, сегодня поговорим о такой хайповой теме, как ИИ-агент OpenClaw. Хотя вру. Не прошло и пару месяцев, как теперь все эякулируют на Hermes, но давайте всё-таки поговорим об OpenClaw.\nЩупать этого агента за вымя, вернее, за клешни будем на примере работы в TerraMaster F4-425 Pro, так как, по заявлениям производителя, их новейшая ОС под названием TOS 7 заточена именно под работу с OpenClaw и вообще вся такая передовая и нарядная.\nTerraMaster утверждает, что это первый AI Native NAS. Предполагается следующая схема работы\nПользователь ↓ OpenClaw ↓ LLM ↓ Инструменты NAS ↓ TOS Производитель обещает:\nуправление NAS голосом автоматизация Docker виртуальные машины Jenkins GitLab REST API более 500 встроенных API создание workflow по текстовому описанию Более подробно можно почитать на официальном сайте - https://www.terra-master.com/pages/tos7\nNote Обзор на TerraMaster F4-425 Pro я делал в прошлом ролике. Это NAS, и он делает нам всем \u0026hellip;. NAS. А главное, что, несмотря на тот факт, что там уже была установлена новая и свежая версия TOS 7, официально вышедшая 23 июня 2026 года, последнее минорное обновление принесло новый дизайн иконок. UI очень заметно преобразился, но я, правда, не понял такого шага от разработчика. А что мешало сразу так сделать? И это, как я уже сказал, маленькое минорное обновление. Странно, но ок.\nЧто такое ИИ-агент OpenClaw # Теперь разберемся, что такое ИИ-агент на примере OpenClaw. Если простыми словами, то именно так, наверное, человек и должен взаимодействовать с ИИ, а не по модели «вопрос - ответ».\nOpenClaw - это открытый AI-агент, который работает локально на вашем компьютере и способен не просто отвечать на вопросы, а выполнять реальные действия: управлять файлами, отправлять сообщения и письма, работать с календарем, запускать программы, искать информацию в интернете и взаимодействовать с десятками сервисов через привычные мессенджеры, такие как Telegram, WhatsApp, Discord и Slack (что характерно, ни один из них не работает в России).\nВ отличие от обычных чат-ботов, OpenClaw получает доступ к инструментам операционной системы и может автоматизировать сложные многошаговые задачи.\nГлавная особенность OpenClaw - полная открытость и возможность запускать его на собственной инфраструктуре. Пользователь сам выбирает модель искусственного интеллекта, настраивает навыки (Skills), подключает внешние сервисы и контролирует, какие действия агенту разрешено выполнять.\nБлагодаря этому OpenClaw подходит как для автоматизации повседневных задач, так и для построения персонального AI-ассистента, не зависящего от облачных сервисов и закрытых экосистем.\nНо вы должны понимать, что по факту, это как тело без мозгов. То есть ИИ-агент - это тело, поэтому обязательно необходимо подключить к LLM, которая будет выступать в качестве мозга\nВопросы безопасности работы с OpenClaw # Несмотря на широкие возможности, OpenClaw имеет и серьезный недостаток - для полноценной работы агенту часто требуются расширенные права доступа к системе и подключаемым сервисам. Он может, а в идеале и должен, получать доступ к файлам, выполнять команды, управлять приложениями и взаимодействовать с различными API, поэтому компрометация агента или его неправильная настройка потенциально способны привести к утечке данных или выполнению нежелательных действий.\nИменно поэтому при использовании OpenClaw рекомендуется придерживаться принципа минимально необходимых привилегий: запускать его в изолированной среде (докер), как минимум запускать в соответствующем VLAN, выдавать доступ только к тем ресурсам, которые действительно нужны, и внимательно контролировать подключаемые инструменты и разрешения. Такой подход позволяет значительно снизить риски без существенной потери функциональности.\nНу и нельзя забывать, что в идеальном сценарии он сам думает за вас: что вам надо, что вам не надо, чего вы хотите. И не исключено, что рано или поздно он поймет, что самое слабое звено - это вы.\nМоя конфигурация # Для работы OpenClaw я использую Ollama, установленную на Windows 11 Pro. Все модели хранятся на отдельном несистемном SSD.\nКонфигурация компьютера:\nОперационная система: Windows 11 Pro Процессор: AMD Ryzen 5 5600X Оперативная память: 64 ГБ DDR4 UDIMM ECC Kingston Видеоускоритель: Intel Arc B580 с 12 ГБ видеопамяти LLM-модель: Qwen3.5:9B При использовании данной конфигурации модель показывает следующую производительность:\nPS C:\\WINDOWS\\system32\u0026gt; ollama run qwen3.5:9b --verbose \u0026gt;\u0026gt;\u0026gt; gfhgfghfghghf --- total duration: 17.4145857s load duration: 251.4912ms prompt eval count: 18 token(s) prompt eval duration: 214.962ms prompt eval rate: 83.74 tokens/s eval count: 955 token(s) eval duration: 16.90268s eval rate: 56.50 tokens/s --- В моем случае скорость генерации составляет 56,5 токена/с, чего более чем достаточно для комфортной работы OpenClaw в режиме интерактивного общения.\nУстановка OpenClaw в TerraMaster # На самом деле установка агента очень простая, но в моем случае не обошлось без приключений. На этапе установки, когда прогресс доходил до 99%, она сбрасывалась в ноль. Я долго не мог понять, в чем дело, пока мне в голову не пришла шальная мысль пропинговать серверы TerraMaster.\nВ итоге в соответствующий address list того, чье имя нельзя называть, были внесены четыре адреса:\napt.terramaster.net 104.26.2.214 104.26.3.214 172.67.71.137 И в следующий раз установка прошла как по маслу.\nПосле того как вы развернули само приложение, я пропинговал свою инстанцию Ollama, потому что именно ее я буду использовать для примеров в этой статье.\ncurl http://айпи_машины_с_развернутой_ollama:11434/v1/models Это нужно для того, чтобы проверить возможность OpenClaw достучаться до Ollama. Если правила firewall у вас настроены правильно, то в результате вы получите список локальных ИИ-моделей, которые уже скачаны.\nТеперь, когда мы установили OpenClaw и проверили доступ к локальным ИИ-моделям, переходим к настройке агента.\nВ дальнейшем, как показала практика, мое железо, а может быть конкретная LLM не очень хорошо взаимодействовала с Opneclaw, но более подробно об этом можно посмотреть в видео по ссылке в начале статьи.\n","date":"12 July 2026","externalUrl":null,"permalink":"/posts/openclaw-on-tos7/","section":"Posts","summary":"Описание работы ИИ-агента OpenClaw на базе Terramaster F4-425PRO c новой операционной системой TOS7","title":"Openclaw на Terramaster OS7","type":"posts"},{"content":"","date":"12 July 2026","externalUrl":null,"permalink":"/tags/terramaster/","section":"Tags","summary":"","title":"Terramaster","type":"tags"},{"content":" Вступление # В этой статье разберем с вами настройку широко известного шлюза Opnsense 26.1\nNote Настоящая статья, посвященная настройке Opnsense, является уникальной для русскоязычной части сети. Ее написание отняло у автора много времени и сил, поэтому, в случае, если вы нашли данную статью полезной и считаете возможным отблагодарить автора, то это можно сделать по соответствующей ссылке на boosty\nУ меня на сайте достаточно много материалов посвященных настройке разных функций Opnsense, но для новичка они носят разрозненный характер и могут быть сложны для усвоения. В связи с этим, собравшись духом и из последних сил, я решился на этот сизифов труд.\nЧто такое OPNsense # OPNsense - это свободно распространяемый дистрибутив межсетевого экрана и маршрутизатора с открытым исходным кодом, построенный на базе FreeBSD. Он позволяет превратить обычный компьютер, мини-ПК или виртуальную машину в полноценное сетевое устройство корпоративного уровня.\nНесмотря на то что OPNsense часто называют просто «фаерволом», его возможности значительно шире. Помимо фильтрации сетевого трафика, система может выполнять функции маршрутизатора, VPN-шлюза, DHCP- и DNS-сервера, балансировщика нагрузки, обратного прокси, IDS/IPS, а также централизованной платформы для управления безопасностью сети.\nNote Часть функций, такие как - обратный прокси, настраиваются с помощью плагинов\nОдним из главных преимуществ OPNsense является сочетание широких возможностей, удобного веб-интерфейса и регулярных обновлений. Большинство задач выполняется через графический интерфейс, поэтому для настройки системы не требуется знание командной строки.\nЧем OPNsense отличается от других решений # Наиболее известными альтернативами OPNsense являются pfSense, MikroTik RouterOS, OpenWrt и различные Linux-дистрибутивы, настроенные вручную в качестве маршрутизатора.\nГлавное отличие OPNsense заключается в том, что система ориентирована на удобство администрирования, прозрачность разработки и регулярное развитие. Проект появился как форк pfSense (который сам по себе форк) и с самого начала сделал акцент на открытой модели разработки, современном интерфейсе управления и предсказуемом цикле обновлений.\nПо сравнению с MikroTik RouterOS OPNsense предоставляет более широкие возможности в области безопасности и интеграции дополнительных сервисов, которые, любители Mikrotik не обижайтесь, легче настраиваются. В отличие от OpenWrt, который в первую очередь предназначен для домашних маршрутизаторов и по факту является просто операционной системой для старых роутеров, OPNsense рассчитана на использование как на специализированном сетевом оборудовании, так и на обычных x86-компьютерах и виртуальных машинах.\nЕсли сравнивать OPNsense с самостоятельно настроенным маршрутизатором на базе Linux, то она избавляет администратора от необходимости вручную собирать отдельные компоненты - такие как firewall, DHCP, DNS, VPN и систему мониторинга. Все основные функции уже интегрированы в единую платформу и доступны через веб-интерфейс.\nКакие задачи решает OPNsense # OPNsense может использоваться как в домашних сетях, так и в инфраструктуре малого и среднего бизнеса. Наиболее распространенные сценарии применения включают:\nорганизацию доступа в Интернет для нескольких сетей и VLAN;\nсоздание правил межсетевого экрана и сегментацию сети;\nразвертывание VPN-серверов и VPN-клиентов (WireGuard, OpenVPN, IPsec);\nнастройку DHCP- и DNS-сервисов;\nпубликацию внутренних сервисов через обратный прокси;\nзащиту сети с помощью IDS/IPS, GeoIP-фильтрации и других механизмов безопасности;\nмониторинг сетевой активности и анализ журналов событий;\nобеспечение высокой доступности (HA) и резервирования сетевой инфраструктуры.\nOPNsense в домашней лаборатории # Для владельцев домашней лаборатории OPNsense может стать одним из центральных элементов сети, так как позволяет построить и настроить сеть, максимально приближенную к корпоративной, не требуя дорогостоящего оборудования и специальных познаний.\nВ домашней лаборатории OPNsense обычно используют для создания отдельных VLAN для серверов, рабочих устройств, IoT и гостевой сети, организации защищенного удаленного доступа через VPN, публикации сервисов в Интернет (есть плагин обратного прокси Caddy), настройки межсетевого экрана между сегментами сети и централизованного управления сетевой безопасностью.\nБлагодаря поддержке виртуализации OPNsense отлично работает в Proxmox VE и других гипервизорах. Поэтому OPNsense можно использовать как виртуальный маршрутизатор, не выделяя отдельное физическое устройство, хотя для максимальной производительности и надежности многие предпочитают устанавливать систему на компактный мини-ПК с несколькими сетевыми интерфейсами.\nСистемные требования # OPNsense нельзя назвать требовательной операционной системой. Она без проблем работает как на компактных мини-ПК, так и в виртуальной машине. Однако требования к оборудованию напрямую зависят от того, какие функции вы планируете использовать.\nДля знакомства с системой или домашней лаборатории достаточно выделить:\nдвухъядерный процессор с архитектурой x86-64;\n4 ГБ оперативной памяти;\nSSD объемом от 16 ГБ;\nне менее двух сетевых интерфейсов - один для подключения к провайдеру (WAN), второй для локальной сети (LAN).\nЕсли же планируется использовать дополнительные возможности, например IDS/IPS, VPN для нескольких пользователей, Zenarmor или большое количество правил фильтрации, объем оперативной памяти лучше увеличить до 8–16 ГБ, а процессор выбрать с запасом производительности.\nОтдельного внимания заслуживают сетевые адаптеры. Так как Opnsense основана на Freebsd, то это возможно один из самых важных вопросов. Для домашней лаборатории лучше использовать устройства на базе контроллеров Intel. Они отличаются стабильной работой, высокой производительностью и полностью поддерживаются FreeBSD, на которой основана OPNsense. С адаптерами Realtek система также работает, но с Realtek есть историческая проблема с драйверами под сетевые устройства, поэтому я бы старался избегать их использования.\nWarning Следует учитывать одну особенность FreeBSD при работе в виртуализированной среде. Если сетевой адаптер не передается в виртуальную машину с OPNsense целиком с помощью PCI Passthrough, а используется виртуальный сетевой интерфейс, то на высокоскоростных каналах (10 Гбит/с и выше) производительность может значительно снижаться. В некоторых сценариях потери пропускной способности достигают 80 %.\nПо этой причине, если вы планируете использовать OPNsense на скоростях 10 Гбит/с и выше, рекомендуется по возможности использовать PCI Passthrough для сетевого адаптера или устанавливать систему непосредственно на физическое оборудование.\nВ качестве платформы можно использовать практически любое современное оборудование: мини-ПК, тонкий клиент, небольшой сервер или виртуальную машину. Многие пользователи запускают OPNsense в Proxmox VE, выделяя ей два или более виртуальных сетевых интерфейса. Такой вариант отлично подходит для домашней лаборатории, поскольку позволяет быстро создавать резервные копии, переносить систему между узлами и экспериментировать с настройками без использования отдельного оборудования.\nNote В видео, ссылка на которое есть в начале настоящей статьи, я все устанавливал на минипк с двумя физическими сетевыми интерфейсами, поэтому в статье я буду придерживаться описания установки и первоначальной настройки именно такой конфигурации. Остальные настройки системы не зависят от способа установки - виртуализация или установка непосредственно на пк.\nУстановка Opnsense # Выбор установочного образа # Первым делом необходимо скачать установочный образ OPNsense с официального сайта проекта. Несмотря на большое количество вариантов, определиться с выбором достаточно просто - все зависит от того, где будет устанавливаться система.\nЕсли OPNsense будет работать на физическом компьютере или мини-ПК с подключенными монитором и клавиатурой, выбирайте образ VGA. Именно он используется в этой статье.\nОбраз DVD предназначен в первую очередь для виртуальных машин и подходит для установки в Proxmox VE, VMware, Hyper-V и другие гипервизоры.\nЕсли устройство оснащено последовательной консолью и управление осуществляется через COM-порт, следует использовать образ Serial. Такой вариант чаще встречается на промышленном оборудовании и некоторых сетевых устройствах.\nТакже на странице загрузки доступен образ Nano, однако в большинстве случаев он не потребуется. Разработчики рекомендуют использовать обычную установку с помощью VGA, DVD или Serial-образов.\nСоздание загрузочной флешки # После загрузки образ необходимо записать на USB-накопитель. Для этого можно воспользоваться Rufus, balenaEtcher или любой другой программой, поддерживающей запись загрузочных образов.\nПосле завершения записи подключите флешку к компьютеру, на который будет устанавливаться OPNsense, и выберите ее в качестве загрузочного устройства в BIOS или UEFI.\nЗапуск установщика # Чтобы сделать настоящую статью чуть более компактной, я не буду включать в данный раздел снимки экрана.\nНе нажимайте никаких клавиш, когда появится запрос Configuration Importer. Когда появится запрос на ручное назначение интерфейсов (Manual Interface Assignment), нажмите любую клавишу. Я предпочитаю настраивать интерфейсы вручную, а не использовать автоматическую настройку. Нажмите Enter, чтобы пропустить настройку LAGG. Нажмите Enter, чтобы пропустить создание VLAN (мы настроим их позже через веб-интерфейс). Введите igc0 в качестве имени интерфейса WAN. Введите igc1 в качестве имени интерфейса LAN . Когда появится запрос на указание дополнительного интерфейса (Optional Interface Name), нажмите Enter, чтобы пропустить этот шаг (мы настроим дополнительные интерфейсы позже). Нажмите Y, затем Enter, чтобы продолжить. В приглашении для входа в систему введите имя пользователя installer и пароль opnsense, чтобы начать установку. Нажмите Enter, чтобы использовать раскладку клавиатуры по умолчанию (если вы используете клавиатуру с американской раскладкой; в противном случае выберите подходящий вариант). Следующим шагом установщик предложит выбрать файловую систему - ZFS или UFS.\nUFS - классическая файловая система FreeBSD. Она потребляет меньше ресурсов и подходит для большинства домашних маршрутизаторов, но она является более \u0026ldquo;хрупкой\u0026rdquo; по сравнению с ZFS.\nZFS предоставляет дополнительные возможности, такие как контроль целостности данных, моментальные снимки (Snapshots) и более гибкое управление хранилищем. Однако она предъявляет более высокие требования к объему оперативной памяти и вычислительным ресурсам.\nДля домашней лаборатории и большинства современных мини-ПК я рекомендую выбрать ZFS, особенно если система будет установлена на SSD и объем оперативной памяти составляет не менее 8 ГБ. Если же вы устанавливаете Opnsense в качестве виртуального роутера, то надо учитывать, что установка ZFS на ZFS не самая лучшая идея, но, в любом случае, выбор файловой системы зависит от вашего конкретного способа установки\nWarning Дешевые китайские ssd или nvme накопители не подходят под использование Opnsense, в особенности в связке с ZFS. Opnsense, как firewall, пишет много логов, zfs тоже. Дешевые диски под такой постоянной нагрузкой будут выходить из строя довольно часто.\nПосле выбора файловой системы останется указать накопитель, на который будет установлена OPNsense. Перед подтверждением внимательно проверьте выбранный диск, так как в процессе установки все данные на нем будут удалены.\nКогда копирование файлов завершится, установщик предложит задать пароль пользователя root. Рекомендую сделать это сразу, чтобы после первого запуска не использовать пароль по умолчанию.\nПервоначальная настройка # Друзья, первоначальная настройка достаточна проста и логична, поэтому я предлагаю вам посмотреть видео, ссылка на которое в начале данной статьи. Но по мере сил, я заполню эту главу. Пока же предлагаю сосредоточиться на более важных и сложных вещах.\nНастройка Unbound DNS # Unbound DNS - это проверяющий (validating), рекурсивный и кэширующий DNS-резолвер, разработанный для высокой производительности и безопасности. Unbound DNS - это программное обеспечение с открытым исходным кодом под лицензией BSD, созданное NLnet Labs, и широко используемое на различных платформах для преобразования доменных имён в IP-адреса. Системные администраторы, интернет-провайдеры и пользователи, заботящиеся о конфиденциальности, часто используют Unbound. Он совместим с OPNsense, pfSense, FreeBSD, Linux, macOS и другими Unix-подобными операционными системами.\nВ этой статье я опишу только основные функции Unbound DNS в Opnsense.\nОсобенности Unbound DNS # Unbound поддерживает DNSSEC (Domain Name System Security Extensions), что гарантирует подлинность и целостность DNS-данных, защищая пользователей от таких угроз, как подмена DNS (DNS spoofing) или отравление кэша (cache poisoning). Он может быть настроен на выполнение рекурсивных запросов и кэширование DNS-результатов для повышения производительности и снижения задержек при последующих обращениях.\nUnbound DNS обладает следующими особенностями:\nЭффективность и легковесность: разработан для минимального использования ресурсов. Гибкость настройки: поддерживает широкий набор параметров конфигурации для сложных и продвинутых установок. DNS-over-TLS/HTTPS: обеспечивает шифрование DNS-запросов для повышения приватности. Поддержка IPv6: полностью совместим с современными интернет-протоколами. Контроль доступа: позволяет настраивать права клиентов на выполнение DNS-запросов к серверу. К сожалению, список настроек Unbound DNS настолько обширен, что описание каждой из них, требует нескольких статей, поэтому в данном случае я обойдусь скриншотами, как я это настраивал на видео\nНиже на скриншоте настройки раздела General\nДалее настройки в разделе Advanced\nНастройка DNS over TLS # DNS over TLS (DoT) - это способ шифрования DNS-запросов, повышающий конфиденциальность и защищённость от их перехвата злоумышленниками. В OPNsense вы можете включить DoT с помощью встроенного DNS-сервера Unbound.\nПорядок настройки # Все DNS-запросы маршрутизируются в открытом виде. Ваш интернет-провайдер или хакер может перехватывать передачи запросов по протоколам UDP и TCP на порту 53 в открытом виде, чтобы скомпрометировать DNS-запросы и ответы сайта. По этой причине мы должны шифровать наши DNS-запросы в целях безопасности. DNS через TLS (DoT) - это протокол безопасности, который использует Transport Layer Security (TLS) для шифрования DNS-трафика и является одним из наиболее распространенных решений безопасности DNS. Основная задача - повысить вашу безопасность и конфиденциальность. Вот несколько преимуществ DNS over TLS:\nПредотвращение манипуляций с DNS со стороны злоумышленника. Исключение атаки типа «человек посередине». Это когда ваш запрос перехватывается и перенаправляется на какой-нибудь фишинговый сайт. Предотвратить шпионаж. Ну для дома это конечно фантасмагория. Включение DoT в Opnsense # Чтобы настроить и включить DoT на брандмауэре OPNsense, выполните следующие действия:\nПерейдите в раздел «Services» → «Unbound DNS» → «DNS over TLS» в веб-интерфейсе OPNsense. Нажмите кнопку «Добавить» со значком + в правом нижнем углу панели. Убедитесь, что отмечен параметр «Включено». Вы можете оставить поле Домен пустым. По умолчанию, если оставить это поле пустым, все запросы будут направляться на указанный сервер. Ввод доменного имени в этом поле приведет к направлению запросов для этого конкретного домена на выбранный сервер. Введите IP-адрес DNS-сервера для пересылки всех запросов, например 8.8.8.8. Установите порт сервера для DoT 853. Введите общее имя DNS-сервера (например, dns.google.com) в поле Verify CN, чтобы проверить его сертификат TLS. DNS-over-TLS уязвим для атак типа «человек посередине», если подлинность сертификатов не может быть подтверждена. Вы можете оставить поле пустым, чтобы принять самоподписанные сертификаты, но это полностью нивелирует смысл того, что мы с вами делаем в этой статье. Нажмите «Сохранить» . Вы можете добавить DNS-сервер IPv6 в качестве вторичного DNS-резолвера. Нажмите «Применить», чтобы активировать настройки. В итоге вы получите что-то вроде такого\nНастройка DNS и DHCP серверов # Чтобы заставить всех клиентов в вашей сети использовать серверы DoT, которые вы определили выше, вы должны правильно настроить свои серверы DNS и DHCP. Вы можете настроить службы DNS и DHCP в OPNsense, выполнив следующие шаги:\nПерейдите в раздел System → Settings → General в меню слева. Убедитесь, что все поля для DNS-серверов пустые. Это делается для того, чтобы гарантировать, что DNS-трафик будет перенаправлен обратно на маршрутизатор. Снимите флажок Allow DNS server list to be overridden by DHCP/PPP on WAN для параметров DNS-сервера. Если этот параметр включен, DNS-серверы, предоставляемые DHCP/PPP-сервером в глобальной сети (WAN) (перевожу на русский, это днс сервера вашего провайдера), будут использоваться для своих предполагаемых функций, таких как предоставление DNS-сервисов. И соответственно они будут иметь приоритет. Чтобы обеспечить безопасную и доверенную среду, рекомендуется использовать правило брандмауэра, которое запрещает любой исходящий трафик DNS на порту 53 при использовании DNS over TLS, который у нас использует порт 53. Если клиенты решат напрямую запрашивать другие серверы имен самостоятельно, можно использовать правило перенаправления NAT для отправки этих запросов на 127.0.0.1:53, который является локальной службой Unbound. Это гарантирует, что эти запросы точно будут отправлены через TLS.\nСписок CN доменов, которые используются для DoT, надо смотреть для соответствующего провайдера.\nДля quad 9 это - dns.quad9.net.\nПросмотр журналов Unbound DNS # Дополнительно можно проверить журналы Unbound DNS, чтобы убедиться, что DNS-запросы действительно передаются по протоколу DNS over TLS (DoT) через порт 853.\nДля этого выполните следующие действия:\nПерейдите в Services → Unbound DNS → Advanced.\nПрокрутите страницу до раздела Logging Settings.\nВключите параметр Log Queries.\nПосле этого Unbound будет записывать в журнал каждую обработанную DNS-запрос. Для каждой записи будут указаны время, IP-адрес клиента, запрашиваемое доменное имя, тип и класс запроса.\nПримечание. Включение журналирования всех DNS-запросов может заметно снизить производительность DNS-сервера, поэтому рекомендуется использовать эту опцию только для диагностики и отключить ее после завершения проверки.\nДля параметра Log Level Verbosity выберите значение Level 2. Этот уровень обеспечивает достаточно подробную информацию для диагностики работы DNS over TLS.\nНажмите Apply, чтобы сохранить изменения.\nЗатем откройте раздел Services → Unbound DNS → Log File.\nВ поле поиска введите 853.\nЕсли DNS over TLS настроен корректно, в журнале появятся записи, подтверждающие, что Unbound обменивается данными с настроенным DNS-резолвером через порт 853. Это означает, что DNS-запросы передаются в зашифрованном виде, а не по обычному протоколу DNS через порт 53.\nСоздание VLAN-интерфейса и настройка DHCP в OPNsense # Ниже приведён пример настройки VLAN WIFI с созданием интерфейса, назначением IP-адреса и включением DHCP-сервера.\n1. Создание VLAN # Перейдите в:\nInterfaces → Devices → VLAN\nНажмите Add и укажите:\nПараметр Значение Name пропуск Parent Interface LAN Tag 10 Description WIFI После этого сохраните настройки.\n2. Назначение интерфейса # Перейдите в:\nInterfaces → Assignments\nВ списке доступных интерфейсов выберите ваш созданный vlan(virtual device)** Нажмите Add После добавления:\nоткройте созданный интерфейс (например, OPT1) переименуйте его в WIFI 3. Настройка интерфейса # Параметр Значение Enable Interface включить IPv4 Configuration Type Static IPv4 IPv4 Address 192.168.10.1/24 Этот адрес будет шлюзом (gateway) для устройств в WIFI.\nСохраните изменения.\n4. Повтор для других VLAN # Аналогично можно создать дополнительные VLAN-сети.\nДля каждой сети необходимо:\nвыбрать уникальный VLAN Tag назначить отдельную подсеть (например, 10.0.X.1/24) создать отдельный DHCP-сервер настроить соответствующие правила firewall Такой подход позволяет легко сегментировать сеть и управлять доступом между устройствами в разных VLAN.\nНастройка DHCP сервера # ISC (Internet Systems Consortium) - организация, разработавшая и на протяжении многих лет поддерживавшая открытый DHCP-сервер ISC DHCP. Начиная с октября 2022 года его активная разработка была прекращена.\nОфициальным преемником ISC DHCP стал Kea DHCP, который также разрабатывается и поддерживается организацией ISC.\nДо версии OPNsense 25.7 сервер ISC DHCP использовался в качестве DHCP-сервера по умолчанию. Но начиная с версии 25.7, эту роль по умолчанию стал выполнять Dnsmasq DNS и DHCP, поскольку он представляет собой легковесное решение, хорошо подходящее для небольших сетей. При этом в состав OPNsense также входит Kea DHCP, поэтому пользователь может самостоятельно выбрать DHCP-сервер, наиболее подходящий для своей инфраструктуры.\nУ меня на сайте есть статья, посвященная переходу с ISC на KEA, но в этой статье я буду показывать настройку только Dnsmasq\nNote Некоторые моменты в видео и соответственно в настоящей статье являются необязательными. Не всем пользователям требуется использовать такие возможности, как статические DHCP-резервирования или переопределения доменов и хостов (Domain/Host Overrides).\nКакой DHCP-сервер выбрать? # Выбор между ними зависит не столько от производительности, сколько от задач, которые вы решаете.\nDnsmasq DHCP # Для большинства домашних пользователей и небольших homelab я рекомендую использовать Dnsmasq. Именно поэтому он стал DHCP-сервером по умолчанию.\nDnsmasq подойдет вам, если:\nдомашняя сеть или Homelab состоит из нескольких VLAN и не требует сложной DHCP-инфраструктуры;\nвы хотите использовать Dnsmasq не только как DHCP-сервер, но и как DNS Forwarder вместо Unbound DNS;\nнеобходимо, чтобы имена устройств, получивших адрес по DHCP, автоматически регистрировались в локальном DNS-сервере;\nвы планируете использовать специальные DNS-алиасы OPNsense для блокировки доступа к определенным доменам.\nKea DHCP # Kea DHCP - это современный преемник ISC DHCP, ориентированный на более сложные сценарии использования.\nЕго стоит выбрать, если:\nтребуется обеспечить отказоустойчивость DHCP-сервера (High Availability);\nв сети используются сложные маршрутизаторы, которым необходимо делегировать IPv6-префиксы (Prefix Delegation).\nКакой DNS-сервер выбрать? # Помимо выбора DHCP-сервера, необходимо определиться и с DNS-службой. В OPNsense доступны два варианта: Dnsmasq DNS и Unbound DNS.\nНесмотря на появление Dnsmasq в качестве DHCP-сервера по умолчанию, основным DNS-сервером по-прежнему остается Unbound DNS. Каждый из вариантов имеет свои преимущества.\nDnsmasq DNS # Dnsmasq стоит выбрать в следующих случаях:\nвы хотите использовать DHCP и DNS в рамках одного сервиса;\nвам необходима поддержка DNS-алиасов OPNsense, которые автоматически преобразуют доменные имена в IP-адреса для использования в правилах межсетевого экрана;\nтребуется максимально простая конфигурация DNS без большого количества дополнительных настроек.\nПри этом стоит учитывать, что возможности Dnsmasq заметно скромнее, чем у Unbound. Он предоставляет меньше параметров конфигурации, а также обладает более ограниченными средствами журналирования и диагностики DNS-запросов.\nUnbound DNS # Unbound DNS - это DNS-сервер, который используется в OPNsense по умолчанию, и именно его я рекомендую большинству пользователей.\nЕго основные преимущества:\nявляется полноценным рекурсивным DNS-резолвером, который может выполнять запросы непосредственно к корневым DNS-серверам, не полагаясь на публичные DNS-провайдеры;\nподдерживает DNS Block Lists (DNSBL), позволяя блокировать рекламу, трекеры и вредоносные домены по аналогии с Pi-hole;\nподдерживает DNS over TLS (DoT), благодаря чему DNS-запросы могут передаваться в зашифрованном виде через доверенные DNS-серверы, например Cloudflare или Quad9;\nпредоставляет подробную статистику и отчеты о работе DNS в разделе Reporting, что значительно упрощает диагностику и анализ запросов.\nСледует помнить, что при использовании DNS over TLS Unbound перестает работать как рекурсивный резолвер. В этом режиме он пересылает запросы выбранному внешнему DNS-серверу по защищенному TLS-соединению.\nИспользование Dnsmasq и Unbound одновременно # В некоторых случаях имеет смысл использовать оба DNS-сервиса одновременно.\nНапример, если в качестве DHCP-сервера используется Dnsmasq, а основным DNS-сервером остается Unbound, клиенты сети продолжают отправлять DNS-запросы в Unbound. При этом запросы к локальным именам хостов автоматически перенаправляются в Dnsmasq, который знает обо всех устройствах, получивших адрес по DHCP.\nТакая схема позволяет объединить преимущества обоих решений: использовать расширенные возможности Unbound и одновременно сохранить автоматическое разрешение имен устройств внутри локальной сети.\nОбщие настройки # Перейдите в раздел:\nServices → Dnsmasq DNS \u0026amp; DHCP → General\nЗдесь находятся основные параметры службы Dnsmasq.\nВключение службы # Первый параметр - Enable.\nВыбор интерфейсов # В поле Interface выберите все интерфейсы, на которых Dnsmasq будет обслуживать DHCP-клиентов.\nОдним из преимуществ Dnsmasq является возможность выбрать сразу несколько интерфейсов в одном месте. .\nИспользование Dnsmasq в качестве DNS # Если вы планируете использовать Dnsmasq не только как DHCP-сервер, но и для разрешения имен устройств в локальной сети, необходимо включить его DNS-функциональность.\nДля этого в разделе DNS измените значение параметра Listen port.\nПараметр Значение Listen port 53053 Настройка переадресации DNS-запросов # В разделе DNS Query Forwarding рекомендуется включить следующий параметр:\nПараметр Значение Do not forward to system defined DNS servers Enabled В этом случае Dnsmasq не будет использовать DNS-серверы, указанные в System → General, а будет отвечать только за разрешение локальных имен хостов. Это предотвращает отправку запросов к неизвестным локальным именам на внешние DNS-серверы.\nПараметры DHCP # В разделе DHCP по умолчанию уже включены три рекомендуемые опции. Их можно оставить без изменений.\nПараметр Значение DHCP FQDN Enabled DHCP local domain Enabled DHCP register firewall rules Enabled Локальный домен # Если поле DHCP default domain оставить пустым, Dnsmasq автоматически будет использовать доменное имя, указанное в разделе System → General. Такое поведение аналогично поведению ISC DHCP.\nПри необходимости здесь можно задать другой домен по умолчанию или указать отдельный домен для каждого DHCP-пула.\nNote Для локальной сети лучше использовать специальный внутренний домен, например .internal. Он официально зарезервирован ICANN для использования в частных сетях. Альтернативой является домен .home.arpa, однако .internal обычно проще воспринимается и запоминается.\nРаздел ISC/KEA DHCP (Legacy) # В нижней части страницы находится раздел ISC/KEA DHCP (Legacy).\nЕсли вы настраиваете Dnsmasq по схеме, описанной в этой статье, включать какие-либо параметры в этом разделе не требуется. Локальное разрешение имен будет работать без использования механизмов совместимости с ISC DHCP и Kea DHCP.\nНастройка диапазонов DHCP # После настройки основных параметров Dnsmasq необходимо создать DHCP-пулы для каждого интерфейса, на котором сервер будет выдавать IP-адреса.\nПерейдите в раздел:\nServices → Dnsmasq DNS \u0026amp; DHCP → DHCP Ranges\nДля каждого интерфейса LAN или VLAN потребуется создать отдельный диапазон адресов.\nNote В отличие от ISC DHCP и Kea DHCP, для Dnsmasq разработчики OPNsense рекомендуют размещать статические DHCP-резервирования внутри DHCP-пула, а не за его пределами.\nСоздание нового DHCP-пула # Нажмите кнопку + в правом нижнем углу страницы и заполните параметры.\nПараметр Значение Interface Интерфейс, для которого создается DHCP-пул Start address Начальный IP-адрес диапазона End address Конечный IP-адрес диапазона Description Необязательно. Например, для сети 192.168.1.0/24 диапазон может выглядеть следующим образом:\nПараметр Значение Start address 192.168.1.2 End address 192.168.1.254 Параметр Subnet mask заполнять не требуется. Поскольку диапазон создается для существующего интерфейса OPNsense, система автоматически определит маску подсети на основании его конфигурации.\nПосле заполнения параметров нажмите Save.\nЕсли в вашей инфраструктуре используется несколько сетей (например, LAN, WIFI, Guest или Management), аналогичным образом создайте DHCP-пулы для каждого соответствующего интерфейса.\nПеренаправление локальных доменов из Unbound DNS в Dnsmasq # Если вы, как и большинство пользователей OPNsense, используете Unbound DNS в качестве основного DNS-сервера, а Dnsmasq только для DHCP и разрешения локальных имен устройств, необходимо настроить перенаправление локальных DNS-запросов.\nТакая схема практически полностью повторяет поведение связки ISC DHCP + Unbound DNS.\nПредполагается, что Unbound DNS уже настроен и используется в качестве основного DNS-сервера. Рассмотрим только параметры, необходимые для интеграции с Dnsmasq.\nНастройка Query Forwarding # Перейдите в раздел:\nServices → Unbound DNS → Query Forwarding\nВ таблице Custom forwarding нажмите кнопку + и создайте новое правило.\nПараметр Значение Domain .internal (или ваш локальный домен) Server IP 127.0.0.1 Server Port 53053 Description Необязательно Здесь используется адрес 127.0.0.1, поскольку Dnsmasq работает на том же устройстве, что и Unbound, а порт 53053 был указан при включении DNS-службы Dnsmasq.\nЕсли для разных сегментов сети используются разные домены (например, .lan, .iot, .guest), аналогичное правило необходимо создать для каждого домена.\nНастройка Reverse DNS # Кроме обычного разрешения имен рекомендуется настроить Reverse DNS (обратное разрешение имен).\nReverse DNS позволяет определить имя устройства по его IP-адресу. Это особенно удобно при анализе журналов OPNsense, когда известно только IP-адрес клиента.\nНастройка выполняется аналогично предыдущему пункту.\nНажмите + и создайте еще одно правило.\nДля параметра Domain используется специальная зона in-addr.arpa.\nНапример, если необходимо обслуживать всю адресацию диапазона 192.168.0.0/16, параметры будут следующими:\nПараметр Значение Domain 168.192.in-addr.arpa Server IP 127.0.0.1 Server Port 53053 Description Необязательно Такое правило позволит выполнять обратное разрешение имен для всех подсетей вида 192.168.x.x.\nЕсли ваша инфраструктура использует другие диапазоны адресов или требуется более точная настройка, можно создать отдельные записи Reverse DNS для каждой локальной сети.\nПосле сохранения изменений Unbound будет автоматически перенаправлять запросы к локальным доменам в Dnsmasq, сохраняя при этом все преимущества Unbound как основного DNS-резолвера.\nНастройка Domain Overrides (необязательно) # Если вы используете Dnsmasq DNS, при необходимости можно настроить Domain Overrides - правила, позволяющие направлять запросы к определенным доменам на другой DNS-сервер.\nТакая возможность полезна, например, если отдельные домены должны обходить DNS-фильтрацию или использовать другой DNS-резолвер.\nDomain Override и Firewall Alias # Одной из интересных особенностей Dnsmasq в OPNsense является возможность связать Domain Override со специальным алиасом межсетевого экрана.\nВ отличие от обычного алиаса, созданного по доменному имени, такой алиас автоматически добавляет не только IP-адреса самого домена, но и всех успешно разрешенных поддоменов.\nЭто значительно упрощает создание правил Firewall, если необходимо разрешить или запретить доступ сразу ко всему домену.\nСоздание Firewall Alias # Перед созданием Domain Override необходимо создать специальный алиас.\nПерейдите в:\nFirewall → Aliases\nСоздайте новый алиас со следующими параметрами:\nПараметр Значение Type External (advanced) После сохранения нажмите Apply.\nТеперь этот алиас можно будет выбрать при создании Domain Override.\nСоздание Domain Override # Перейдите в раздел:\nServices → Dnsmasq DNS \u0026amp; DHCP → Domains\nСоздайте новое правило и в качестве DNS-сервера укажите локальный адрес Dnsmasq.\nПараметр Значение Server IP 127.0.0.1 Server Port 53053 Firewall Alias ранее созданный алиас После этого OPNsense будет автоматически наполнять выбранный алиас IP-адресами домена и его поддоменов.\nВажно\nЭта функция очень удобна, но использовать ее следует с осторожностью. Если домен обслуживается большим количеством серверов или использует CDN, алиас может содержать сотни IP-адресов. Применение такого алиаса в правилах Firewall способно привести к неожиданным результатам - например, разрешить или заблокировать доступ к сторонним сервисам, которые используют те же IP-адреса. По этой причине разработчики OPNsense рекомендуют использовать подобные алиасы прежде всего для списков разрешения (Allow List), а не для блокировки.\nСледует также учитывать, что OPNsense не отслеживает значение TTL DNS-записей для такого алиаса. Если IP-адреса домена изменятся, они не будут обновлены автоматически до очистки и повторного заполнения алиаса. В результате правила межсетевого экрана могут некоторое время использовать устаревшие адреса.\nНастройка Hosts (необязательно) # Вкладка Hosts предназначена не только для хранения статических DHCP-резервирований, но и для создания переопределений DNS-имен (Host Overrides), если в Dnsmasq включена DNS-служба.\nПри открытии окна Edit Host Override можно заметить, что оно объединяет параметры как DHCP, так и DNS.\nСоздание нового статического резервирования # Чтобы добавить новое устройство, нажмите кнопку + и заполните необходимые поля.\nПараметр Значение Host Имя устройства IP address Статический IP-адрес Hardware address MAC-адрес устройства Domain Необязательно Если поле Domain оставить пустым, будет использован домен, указанный в общих настройках системы (System → General).\nИспользование Alias Record # Помимо статических DHCP-записей, Dnsmasq позволяет создавать дополнительные DNS-псевдонимы (Alias Record).\nЭто может быть полезно, например, при использовании обратного прокси (Reverse Proxy), когда несколько доменных имен должны указывать на одно устройство.\nКроме того, можно создавать записи CNAME, что особенно удобно для устройств с динамическими IPv4-адресами.\nDnsmasq или Unbound для Host Overrides? # Если Unbound DNS настроен на перенаправление локальных запросов в Dnsmasq, переопределения имен можно создавать двумя способами:\nв разделе Hosts Dnsmasq;\nс помощью Host Overrides в Unbound DNS.\nОба варианта будут работать корректно.\nЕсли вы уже использовали Host Overrides в Unbound DNS, переносить их в Dnsmasq не обязательно. Можно оставить существующую конфигурацию без изменений - Unbound продолжит использовать ее, а локальные имена устройств, зарегистрированных в Dnsmasq, также будут успешно резолвиться.\nНастройка Firewall # В этой части статьи я кратко рассмотрю основы настройки фильтрации пакетов в OPNsense и покажу, как создаются и применяются правила межсетевого экранирования на простых примерах.\nКак работает межсетевой экран OPNsense? # Ниже кратко рассмотрены основные принципы работы межсетевого экрана OPNsense и базовые понятия, необходимые для понимания механизма фильтрации пакетов.\nПравила (Rules) # OPNsense использует межсетевой экран с отслеживанием состояния соединений (Stateful Packet Filter). Он позволяет разрешать или запрещать прохождение сетевых пакетов между определенными сетями, а также управлять тем, каким образом пакеты пересылаются через устройство.\nПравила межсетевого экранирования в OPNsense представляют собой политики безопасности, которые применяются к сетевому трафику и организованы по интерфейсам.\nНиже рассмотрены основные элементы правила.\nДействия (Actions) # Каждому правилу можно назначить одно из трех действий.\nPass (Разрешить) # Разрешает прохождение сетевого трафика.\nBlock (Блокировать) # Запрещает прохождение трафика без уведомления клиента о том, что пакет был отброшен.\nЭто рекомендуемый вариант для недоверенных сетей, например Интернета.\nReject (Отклонить) # Запрещает прохождение трафика и отправляет клиенту уведомление об отказе.\nДанный режим поддерживается только протоколами TCP и UDP:\nдля TCP отправляется пакет RST (Reset); для UDP возвращается сообщение ICMP Destination Unreachable. Note Примечание При блокировке доступа во внутренних сетях зачастую удобнее использовать Reject, поскольку клиент сразу получает уведомление об отказе и не ожидает завершения тайм-аута. Для недоверенных сетей (например, Интернета) рекомендуется использовать Block, чтобы не предоставлять потенциальному злоумышленнику никакой дополнительной информации о работе межсетевого экрана.\nПравило «Разрешить всё» (Allow All Rule) # После установки OPNsense и первоначальной настройки интерфейсов LAN и WAN система автоматически создает несколько правил:\nправило защиты от блокировки доступа (Web Administration Anti-Lockout Rule); правило Allow All для IPv4; правило Allow All для IPv6. Эти правила выполняют две важные функции:\nпредотвращают потерю доступа к веб-интерфейсу управления OPNsense; предоставляют устройствам локальной сети (LAN) полный доступ в Интернет и к другим сетям, расположенным за межсетевым экраном. Поэтому любое устройство, подключенное непосредственно к маршрутизатору (или к коммутатору, подключенному к нему), сразу получает возможность работать в сети без дополнительной настройки правил.\nЕсли правило Allow All удалить или отключить, весь исходящий трафик из локальной сети будет заблокирован. Исключением останется только доступ к веб-интерфейсу управления OPNsense.\nПочему правило Anti-Lockout не рекомендуется использовать в корпоративной сети # Хотя правило Anti-Lockout очень удобно для домашнего использования, в корпоративной среде его применение считается небезопасным.\nПричина заключается в том, что оно позволяет любому устройству локальной сети получить доступ к интерфейсам управления межсетевым экраном, включая:\nWeb GUI; SSH-консоль. Это создает серьезную угрозу информационной безопасности и может привести к компрометации системы или утечке данных.\nПоэтому в корпоративных сетях рекомендуется:\nотключить правило Anti-Lockout; создать собственное правило, разрешающее доступ к управлению только администраторам или доверенным устройствам. Как посмотреть правила по умолчанию # Чтобы просмотреть автоматически созданные правила:\nПерейдите в Firewall → Rules → LAN. В верхней части списка правил нажмите значок раскрывающегося списка рядом с пунктом Automatically generated rules. После этого будут отображены автоматически созданные правила, включая:\nDefault Anti-Lockout Rule; Allow LAN to Any. Порядок обработки правил в OPNsense # При поступлении сетевого пакета OPNsense проверяет правила в следующем порядке:\nFloating Rules (плавающие правила); Interface Groups (правила групп интерфейсов); Interface Rules (правила отдельных интерфейсов). Автоматически создаваемые внутренние правила системы обычно регистрируются первыми.\nПараметр Quick и порядок срабатывания правил # По умолчанию большинство правил создаются с включенным параметром Quick.\nЕсли Quick включен, используется принцип:\nNote Первое совпавшее правило побеждает (First Match Wins).\nКак только пакет соответствует какому-либо правилу:\nдальнейшая проверка прекращается; последующие правила игнорируются. Если параметр Quick отключен, применяется другой алгоритм:\nNote Побеждает последнее совпавшее правило (Last Match Wins).\nТакой режим используется значительно реже и подходит для реализации специальных политик фильтрации.\nНапример, именно этот механизм применяется в стандартном правиле Default Deny: если пакет не подошел ни под одно правило, он будет отброшен.\nПочему порядок правил имеет значение # Правила OPNsense проверяются сверху вниз.\nПоэтому их расположение напрямую влияет на результат обработки трафика.\nКак только пакет соответствует правилу:\nPass; Block; Reject, дальнейшая обработка прекращается.\nИменно поэтому рекомендуется соблюдать следующий принцип:\nнаиболее специфичные правила размещать в начале списка; более общие - ближе к концу. Например:\nразрешить пользователям LAN доступ только к HTTP и HTTPS; затем разрешить DNS; после этого добавить другие необходимые правила; в самом конце оставить правило Deny All или Allow All, которое будет обрабатывать весь трафик, не попавший под предыдущие правила. Такой подход делает конфигурацию более понятной и значительно повышает безопасность сети.\nНаправление проверки трафика (Direction) # Правила могут применяться к трафику в двух направлениях:\nIncoming (In) - входящий трафик; Outgoing (Out) - исходящий трафик. По умолчанию OPNsense фильтрует входящий трафик (In).\nЭто означает, что правило необходимо создавать на том интерфейсе, через который пакет поступает в межсетевой экран.\nПример # Предположим, необходимо разрешить подключения по HTTPS (порт 443) из Интернета к внутреннему веб-серверу. В этом случае правило следует создавать на интерфейсе WAN, поскольку именно через него пакеты поступают в OPNsense из внешней сети. После этого правило разрешит входящие подключения на TCP-порт 443 к указанному серверу.\nНастройки правил межсетевого экрана # Некоторые параметры правил используются исключительно для удобства администрирования и никак не влияют на обработку сетевого трафика. Использование понятных названий и описаний значительно облегчает поиск правил и анализ событий в журнале межсетевого экрана.\nОписание параметров # Параметр Описание Category Категория, к которой относится правило. Может использоваться для фильтрации правил в списке. Description Произвольное текстовое описание правила. Рекомендуется использовать информативные комментарии. Основные параметры # Ниже приведены параметры, которые используются чаще всего.\nПараметр Описание Action Действие правила: Pass, Block или Reject. Disabled Позволяет временно отключить правило без его удаления. Полезно при тестировании или для редко используемых политик. Interface Интерфейс, к которому применяется правило. Правила можно копировать между интерфейсами, изменяя только целевой интерфейс. TCP/IP Version Определяет, применяется ли правило к IPv4, IPv6 или сразу к обеим версиям протокола. Protocol Сетевой протокол. Наиболее часто используются TCP и UDP. Source Исходный IP-адрес или сеть. При использовании алиасов можно объединять IPv4- и IPv6-адреса в одном правиле. Source / Invert Инвертирует условие источника. Например, «не 172.16.0.0/24». Destination Адрес или сеть назначения. Поддерживается использование алиасов. Destination / Invert Инвертирует условие назначения. Destination Port Range Позволяет указать сервис по имени (HTTP, HTTPS и т.д.) или номеру порта (включая диапазоны). Также можно использовать алиасы. Log При срабатывании правила создается запись в журнале. Проверить ее можно в Firewall → Log Files → Live View. Алиасы (Aliases) # Алиасы - один из самых полезных инструментов OPNsense. Они позволяют существенно сократить количество правил и сделать конфигурацию более понятной.\nАлиас представляет собой именованный список:\nузлов;\nсетей;\nпортов;\nMAC-адресов;\nстран;\nдругих объектов.\nВместо того чтобы перечислять множество IP-адресов или портов в каждом правиле, достаточно указать имя соответствующего алиаса.\nВ OPNsense уже имеются встроенные алиасы, например:\nSSH\nHTTP\nHTTPS\nLAN net\nLAN address\nLAN interface\nDNS\nИспользование встроенных алиасов делает правила значительно более читаемыми.\nПреимущества использования алиасов # Использование алиасов позволяет:\nписать более понятные правила;\nоблегчить сопровождение конфигурации;\nуменьшить количество правил;\nобъединять множество объектов в одно правило;\nповысить производительность межсетевого экрана за счет уменьшения числа проверяемых правил.\nИными словами, правильно организованные алиасы позволяют существенно снизить сложность конфигурации.\nУправление алиасами # Создание, изменение и удаление алиасов выполняется через:\nFirewall → Aliases\nПри просмотре правил переходить в раздел Aliases необязательно.\nЕсли навести курсор мыши на имя алиаса в правиле, OPNsense покажет всплывающую подсказку, содержащую:\nсодержимое алиаса;\nего описание.\nЭто значительно упрощает анализ существующих правил.\nТипы алиасов # OPNsense поддерживает несколько видов алиасов.\nТип Описание Hosts Отдельные IP-адреса, диапазоны адресов или доменные имена (FQDN). Networks Подсети в формате CIDR либо сети-исключения. Ports Один порт или диапазон портов. MAC addresses Полные или частичные MAC-адреса. URL (IPs) Список IP-адресов, который загружается один раз. URL Tables (IPs) Список IP-адресов, автоматически обновляемый через заданные интервалы времени. GeoIP Страны или целые регионы мира. Network Group Объединяет несколько сетевых алиасов в один. External Внешний алиас, содержимое которого управляется сторонними программами или API. Hosts # Алиасы типа Hosts могут содержать:\nотдельные IP-адреса;\nдиапазоны IP-адресов;\nлокальные имена узлов;\nполные доменные имена (FQDN).\nДля исключения адресов используется символ !.\nНапример:\n!172.16.0.10 означает исключение данного адреса.\nВ одном алиасе допускается объединение различных типов записей:\nyoutube.com, 172.16.1.1, 192.168.10.1, web_server Допустимые примеры # IPv4-адрес:\n172.16.1.10 или\n!172.16.1.10 Диапазон адресов:\n172.16.1.10-172.16.1.15 Локальное имя:\ndbserver или\n!dbserver Полное доменное имя:\nyoutube.com или\n!youtube.com Также поддерживаются IPv6-адреса.\nNetworks # Для сетевых алиасов используется запись CIDR (Classless Inter-Domain Routing).\nНапример:\n/32 - один IPv4-адрес;\n/128 - один IPv6-адрес;\n/24 - сеть с маской 255.255.255.0;\n/64 - стандартная подсеть IPv6.\nКак и в алиасах Hosts, здесь допускается использование исключений:\n!172.16.0.0/24 Кроме CIDR можно применять Wildcard Mask, позволяющую описывать диапазоны адресов.\nTip Чтобы выбрать все маршруты, заканчивающиеся на .1 в сети 172.16.х.1 можно использовать запись вида 172.16.0.1/0.0.255.0\nPorts # Порты могут задаваться:\nодним номером;\nдиапазоном через двоеточие.\nНапример:\n20:25 означает диапазон портов от 20 до 25.\nДопускаются значения от 0 до 65535.\nМожно перечислять сразу несколько портов и диапазонов:\n21,8000:8080 MAC Addresses # Алиасы данного типа содержат MAC-адреса.\nДопускается использование как полного, так и частичного адреса.\nНапример:\nF4:90:EA позволит выбрать все устройства данного производителя.\nURL Tables # URL Table позволяет автоматически получать список IP-адресов с удаленного сервера.\nНаиболее известный пример - списки Spamhaus Don\u0026rsquo;t Route Or Peer (DROP) или FireHole.\nПодобные списки часто используются для автоматической блокировки вредоносных адресов.\nGeoIP # Алиасы типа GeoIP позволяют разрешать или запрещать доступ:\nотдельным странам;\nцелым регионам или континентам.\nДля использования GeoIP необходимо:\nоткрыть Firewall → Aliases → GeoIP;\nнастроить источник данных;\nполучить базу GeoIP.\nНаиболее распространенным поставщиком является MaxMind.\nДля работы потребуется зарегистрироваться в сервисе MaxMind и получить базу географических диапазонов IP-адресов.\nNetwork Group # Network Group объединяет несколько сетевых алиасов в один.\nТакой алиас может содержать:\nсети;\nотдельные хосты;\nдругие совместимые алиасы.\nГлавное преимущество данного типа заключается в том, что OPNsense не позволит случайно объединить несовместимые типы алиасов.\nExternal # Алиасы типа External не управляются штатным механизмом OPNsense.\nИх содержимое формируется внешними приложениями, API или скриптами.\nТакие алиасы удобно использовать, например:\nдля интеграции с системами защиты;\nдинамической блокировки адресов;\nавтоматического управления списками доступа.\nТекущее содержимое можно посмотреть в разделе:\nFirewall → Diagnostics → pfTables\nВложенные алиасы (Nesting Aliases) # Все типы алиасов поддерживают вложенность.\nЭто позволяет объединять несколько существующих алиасов в один более общий.\nНапример, если имеются два алиаса:\nwebserver\nemailserver\nможно создать третий алиас:\ndmzservers в который будут входить оба предыдущих.\nПосле этого:\nотдельные правила можно применять только к webserver;\nтолько к emailserver;\nлибо сразу ко всей группе dmzservers.\nТакой подход значительно упрощает сопровождение крупных конфигураций межсетевого экрана и позволяет избежать дублирования правил.\nПримеры правил межсетевого экрана OPNsense # Ниже приведены наиболее распространенные примеры правил OPNsense, которые могут оказаться полезными как домашним пользователям, так и владельцам небольших компаний при первоначальной настройке межсетевого экрана.\n1. Разрешение использования только определённых DNS-серверов # Одной из первых мер по повышению безопасности сети является запрет использования сторонних DNS-серверов. Это предотвращает попытки пользователей или вредоносного ПО обойти политики фильтрации, родительского контроля или DNS-блокировки.\nРекомендуется разрешить клиентам использовать только:\nвстроенный DNS-сервер OPNsense;\nсобственный локальный DNS-сервер;\nлибо доверенный внешний DNS-сервис с функциями фильтрации.\nДля этого необходимо создать два правила.\nШаг 1. Разрешить доступ к внутреннему DNS-серверу # Параметр Значение Action Pass Protocol TCP/UDP Source any Source Port any Destination LAN address Destination Port DNS (53) Description Allow internal DNS Если используется DNS Resolver или DNS Forwarder OPNsense, DNS-служба автоматически работает на IP-адресе интерфейса LAN. Именно поэтому:\nIP-адрес шлюза;\nIP-адрес DNS-сервера\nво многих домашних сетях совпадают.\nЕсли используется отдельный DNS-сервер, вместо LAN address необходимо указать его IP-адрес.\nШаг 2. Заблокировать все остальные DNS-серверы # После разрешения собственного DNS необходимо создать правило блокировки.\nПараметр Значение Action Block Protocol TCP/UDP Source any Source Port any Destination any Destination Port DNS (53) Description Block external DNS OPNsense проверяет правила сверху вниз.\nПоэтому:\nсначала пакет попадает под правило Allow Internal DNS;\nесли DNS-сервер не совпадает с разрешенным, пакет доходит до правила Block External DNS и блокируется.\nТаким образом:\nвнутренний DNS продолжает работать;\nобращения ко всем остальным DNS-серверам блокируются.\nПосле создания правил рекомендуется переместить их в начало списка правил и нажать Apply Changes.\n2. Разрешение доступа к локальным сервисам между VLAN # Одним из основных принципов информационной безопасности является сегментация сети.\nКритически важные серверы рекомендуется размещать в отдельных VLAN и разрешать к ним доступ только тем пользователям, которым это действительно необходимо.\nНапример, сервер базы данных отдела кадров должен быть доступен исключительно компьютерам сотрудников HR.\nПример: доступ к серверу базы данных Postgres # Создадим следующие алиасы.\nАлиас типа Hosts, содержащий список айпи адресов с которых можно получить доступ до базы данных\nНапример:\n10.10.10.11-10.10.10.20 Postgres\nАлиас типа Hosts, содержащий IP-адрес сервера базы данных.\nНапример:\n192.168.1.157 SQL\nАлиас типа Ports, содержащий стандартный порт Postgres.\n5432/TCP Создание правила # Параметр Значение Action Pass Protocol TCP Source название алиаса Destination Postgres Destination Port SQL Description Allow access to Postgres Database Server Такое правило разрешит только конкретным устройствам подключаться к серверу с базой данных Postgres\nДля остальных устройств рекомендуется использовать правило Deny All либо отдельное правило блокировки.\nПосле создания правила жмем Apply Changes.\nПример: доступ из LAN к веб-серверу в DMZ # Рекомендуется размещать публичные веб-серверы в отдельной сети DMZ (Demilitarized Zone).\nПредположим, веб-сервер имеет адрес:\n192.168.10.20 Создаем алиас:\nWeb_server После этого создаем правило.\nПараметр Значение Action Pass Protocol TCP Source LAN net Destination Web_server Destination Port HTTPS Description Allow access to Web Server После применения изменений пользователи локальной сети смогут подключаться к веб-серверу по HTTPS.\n3. Блокировка доступа между VLAN # По возможности следует запрещать любое ненужное взаимодействие между внутренними сегментами сети.\nПо умолчанию OPNsense не разрешает обмен трафиком между VLAN, если только внизу списка правил не находится правило Allow All.\nОднако многие домашние пользователи предпочитают использовать правило Allow All, разрешающее весь трафик, кроме явно запрещенного.\nВ этом случае необходимо вручную запретить доступ к другим VLAN.\nИначе устройства различных сегментов смогут свободно взаимодействовать друг с другом, что полностью нивелирует преимущества сетевой сегментации.\n3.1 Создание алиаса # Создайте алиас Private_IP_Ranges в разделе:\nFirewall → Aliases\nОн должен содержать все диапазоны частных сетей:\n10.0.0.0/8\n172.16.0.0/12\n192.168.0.0/16\n3.2 Создание правила # Параметр Значение Action Block Protocol any Source LAN net Destination Private_IP_Ranges Destination Port any Description Block access to all other private networks 4. Разрешение всего остального трафика # В конце списка правил OPNsense всегда существует неявное правило Deny All.\nПоэтому администратор обычно явно разрешает только необходимые службы.\nОднако домашним пользователям бывает сложно определить все необходимые порты для современных устройств:\nтелевизоров;\nигровых приставок;\nсмартфонов;\nноутбуков;\nIoT-устройств.\nПоэтому для домашних сетей нередко применяется следующая схема:\nв начале списка размещаются правила блокировки;\nпосле них - необходимые разрешающие правила;\nв конце добавляется правило Allow All.\nТакой подход значительно упрощает эксплуатацию домашней сети, хотя для корпоративной инфраструктуры он не рекомендуется.\n5. Полный доступ для администратора # Во время устранения неисправностей системному администратору часто требуется быстро получить доступ к любому устройству сети.\nПоэтому рекомендуется создать отдельное правило, которое будет располагаться выше всех правил блокировки.\n5.1 Создание алиаса # Создайте алиас:\nadmins в который добавьте:\nрабочий компьютер администратора;\nноутбук;\nсервер администрирования;\nдругие доверенные устройства.\n5.2 Создание правила # Параметр Значение Action Pass Interface LAN Protocol any Source admins Destination any Destination Port any Description Allow admin devices access to anywhere without any restriction На интерфейсе, где находятся устройства администратора (например LAN):\nсоздайте правило Pass;\nисточником выберите алиас admins;\nостальные поля оставьте Any.\nТакое правило позволит администраторам получать доступ к любым устройствам сети независимо от других ограничений.\nПоскольку правила OPNsense обрабатываются сверху вниз, данное правило рекомендуется разместить в самом начале списка.\nDestination NAT (Port Forward) # Перенаправление портов (Destination NAT) # Когда несколько устройств локальной сети используют один внешний IP-адрес, все входящие подключения из Интернета поступают на этот единственный адрес.\nБез дополнительных настроек OPNsense не может определить, какому внутреннему устройству следует передать входящий трафик. В результате такие подключения будут отклоняться.\nЭта проблема решается с помощью Destination NAT (DNAT), также известного как Port Forward (перенаправление портов).\nТипичный пример использования - публикация веб-сервера, расположенного во внутренней сети. Чтобы сервер стал доступен из Интернета, необходимо перенаправить на него входящие подключения к портам:\n80/TCP (HTTP); 443/TCP (HTTPS). Где настраивается Destination NAT # Для создания правил перенаправления портов перейдите в веб-интерфейсе OPNsense:\nFirewall → NAT → Destination NAT (Port Forward)\nВ данном разделе отображается список всех существующих правил Destination NAT, а также доступны функции их создания, редактирования и удаления.\nПараметры правила Destination NAT # При создании нового правила доступны следующие основные параметры.\nПараметр Описание Disabled Отключает правило без его удаления. Пока параметр включен, правило не применяется. Sequence Определяет порядок обработки правил. OPNsense проверяет правила последовательно сверху вниз в соответствии с их порядком. Categories Позволяет присвоить правилу одну или несколько категорий для удобной организации и фильтрации. Description Произвольное описание правила. Рекомендуется указывать понятное название, чтобы в дальнейшем было проще определить его назначение. Параметры интерфейса (Interface) # При создании правила Destination NAT (Port Forward) необходимо указать, на каком интерфейсе и для какого типа трафика оно будет применяться.\nПараметр Описание Interface Интерфейс (или несколько интерфейсов), на котором будет приниматься входящий трафик. Обычно для публикации сервисов используется интерфейс WAN. Version Версия IP-протокола, к которой применяется правило: IPv4, IPv6 или обе версии одновременно. Protocol Сетевой протокол, который должен соответствовать правилу. Чаще всего используются TCP, UDP или комбинация TCP/UDP, однако доступны и другие поддерживаемые протоколы. Параметры источника (Source) в правилах OPNsense # При создании правил фильтрации и NAT в OPNsense важно правильно определить параметры, связанные с источником трафика.\nПараметр Описание Invert Source Инвертирует условие источника. Вместо указанного диапазона будет соответствовать весь трафик, кроме него. Например, «все, кроме 192.168.1.0/24». Source Address Указывает исходную сеть, IP-адрес или алиас, с которого должен приходить трафик. Можно использовать как отдельные хосты, так и целые сети или группы. Source Port Определяет исходный порт или диапазон портов. Обычно используется реже, так как клиентские порты назначаются динамически. Однако может быть полезен для специализированных сценариев фильтрации. Параметры назначения (Destination) в правилах OPNsense # При настройке правил фильтрации и NAT важно точно определить, куда направляется трафик. Для этого используются параметры назначения (Destination).\nПараметр Описание Invert Destination Инвертирует условие назначения. Вместо указанного адреса или сети правило будет применяться ко всем адресам, кроме указанных. Destination Address IP-адрес, сеть или алиас, на который должен быть направлен трафик. Может включать как отдельные хосты, так и группы адресов. Destination Port Порт или диапазон портов назначения. Используется для фильтрации конкретных сервисов (например, HTTP, HTTPS, DNS и т.д.). Параметры перенаправления (Redirect / Translation) # В правилах Destination NAT (Port Forward) параметры перенаправления определяют, куда именно будет отправлен входящий трафик после обработки.\n💡 Принцип работы # Перенаправление (NAT) преобразует исходный внешний адрес назначения (например, публичный IP-адрес firewall) в внутренний адрес сервера.\nНапример:\nвнешний IP: 203.0.113.10:443\nвнутренний сервер: 192.168.1.50:443\nПосле применения правила соединение автоматически перенаправляется на внутренний хост.\nПараметры перенаправления # Параметр Описание Redirect Target IP Внутренний IP-адрес, на который будет перенаправлен входящий трафик. Обычно это сервер в локальной сети (LAN или DMZ). Redirect Target Port Порт на внутреннем хосте, на который будет перенаправлено соединение. Он может совпадать с внешним портом или отличаться (например, 80 → 8080). Pool Options Определяет способ распределения трафика при использовании нескольких внутренних IP-адресов (балансировка нагрузки или выбор целевого сервера по определённому алгоритму). Дополнительные параметры (Options) в Destination NAT # При настройке правил Destination NAT (Port Forward) в OPNsense доступны дополнительные опции, которые управляют поведением правила, синхронизацией и взаимодействием с firewall rules.\nПараметры Options # Параметр Описание No XMLRPC Sync Исключает данное правило из синхронизации с HA-партнёрами (High Availability). Используется в кластерах, где не все NAT-правила должны копироваться на второй узел. NAT Reflection Управляет режимом NAT reflection (hairpin NAT). Позволяет внутренним клиентам обращаться к сервисам через внешний IP-адрес. Может быть включён, отключён или наследовать глобальные настройки. Set Tag Присваивает тег пакетам, которые соответствуют этому NAT-правилу. Используется для последующей обработки другими правилами firewall. Match Tag Позволяет применять правило только к пакетам, уже имеющим определённый тег. Используется для сложных сценариев маршрутизации и фильтрации. Firewall rule (генерация правил firewall) # OPNsense может автоматически создавать соответствующие правила межсетевого экрана на основе NAT-конфигурации.\nДоступны следующие варианты:\nОпция Описание Manual (рекомендуется) Администратор вручную создаёт firewall rules. Это наиболее гибкий и рекомендуемый вариант. Pass (auto rule) Автоматически разрешает трафик через NAT-правило. Такие правила не отображаются во вкладке Firewall Rules. Generate Interface Rules Создаёт правила на интерфейсе автоматически, которые затем могут быть переопределены более приоритетными правилами. Важное замечание # При использовании автоматической генерации правил необходимо учитывать:\nправило NAT и firewall rule должны соответствовать одному и тому же целевому адресу;\nавтоматические правила могут быть перекрыты более приоритетными правилами интерфейса;\nдля сложных конфигураций рекомендуется использовать ручное управление правилами, чтобы избежать конфликтов и неожиданных блокировок.\nCrowdSec (OPNsense plugin) # CrowdSec - это система поведенческой защиты, которая анализирует логи и автоматически блокирует подозрительную активность. В отличие от классического firewall, он работает не по IP-спискам, а по сценариям поведения (bruteforce, сканирование, аномальные запросы и т.д.).\nВ OPNsense плагин CrowdSec устанавливается из официальных репозиториев и включает сразу три компонента:\nLog Processor (анализ логов, ранее IDS) LAPI (локальный API для принятия решений) Remediation Component (блокировка трафика, ранее IPS) Установка плагина # Перейдите в:\nSystem → Firmware → Plugins\nНайдите и установите:\nos-crowdsec\nПосле установки автоматически будут развернуты следующие пакеты:\ncrowdsec crowdsec-firewall-bouncer os-crowdsec ⚠️ Важно: не запускайте и не настраивайте сервисы вручную через shell. В OPNsense управление CrowdSec полностью выполняется через интерфейс плагина.\nПроверка установки # После установки обновите страницу и перейдите в:\nServices → CrowdSec → Overview\nЗдесь можно проверить:\nзапущен ли Log Processor активен ли LAPI работает ли Remediation Component загружены ли collections и сценарии Если все отображается корректно - базовая установка завершена.\nНастройки CrowdSec # Далее перейдите в:\nServices → CrowdSec → Settings\nПо умолчанию включены три основных компонента:\nLog Processor LAPI Remediation Component Их можно отключить только для тестирования или при нестандартной архитектуре (например, если LAPI вынесен на отдельный сервер).\nПоведение по умолчанию # Начиная с CrowdSec 1.6.3, частные IP-адреса (LAN диапазоны) автоматически исключаются из блокировок.\nЭто означает, что адреса вида:\n192.168.x.x 10.x.x.x 172.16.x.x не будут блокироваться даже при совпадении со сценариями атак.\nЕсли необходимо изменить это поведение и разрешить блокировку внутренних адресов, можно удалить соответствующий whitelist-парсер:\ncscli parsers remove crowdsecurity/whitelists Тестирование работы Remediation (IPS) # Для проверки работы блокировки можно вручную добавить тестовое правило.\n⚠️ Важно: при выполнении команды ваш SSH-сеанс может быть разорван.\ncscli decisions add -t ban -d 2m -i \u0026lt;your_ip_address\u0026gt; После выполнения:\nваш текущий IP будет заблокирован на 2 минуты повторное подключение с этого IP будет невозможно Как узнать свой внешний IP # Если вы подключены по SSH, IP можно получить так:\necho $SSH_CLIENT | awk \u0026#39;{print $1}\u0026#39; или:\nw -h | awk \u0026#39;{print $3}\u0026#39; | sort -u Remote LAPI (опционально) # По умолчанию LAPI (локальный API CrowdSec) работает прямо на OPNsense. Однако в более сложных схемах его можно вынести на отдельный сервер.\nЭто имеет смысл, если:\nOPNsense работает на слабом железе уже есть центральный CrowdSec сервер требуется единая точка управления ⚠️ Важно: при использовании удаленного LAPI часть информации в интерфейсе OPNsense может отображаться некорректно (например, список машин и bouncers).\nНастройка удаленного LAPI # Предположим, что у вас уже есть отдельный LAPI сервер, доступный по сети.\n1. Настройка LAPI сервера # На сервере CrowdSec откройте конфигурацию:\n/usr/local/etc/crowdsec/config.yaml (FreeBSD)/etc/crowdsec/config.yaml (Linux) Измените параметр:\napi.server.listen_uri например:\n192.168.122.214:8080 Также обновите:\nlocal_api_credentials.yaml в формате:\nhttp://192.168.122.214:8080 После этого перезапустите CrowdSec.\n2. Настройка OPNsense # В OPNsense:\nотключите Enable LAPI включите Manual LAPI configuration примените настройки 3. Регистрация OPNsense в LAPI # На OPNsense выполните:\ncscli lapi register -u http://192.168.122.214:8080 4. Проверка на LAPI сервере # cscli machines list При необходимости:\ncscli machines validate \u0026lt;machine_id\u0026gt; 5. Добавление bouncer’а # cscli bouncers add opnsense В ответ вы получите API key, например:\na8605055a065fd06b86ecac84e9e9ae4 6. Настройка bouncer на OPNsense # Откройте файл:\n/usr/local/etc/crowdsec/bouncers/crowdsec-firewall-bouncer.yaml Укажите:\napi_key api_url После этого перезапустите сервис CrowdSec:\nservice oscrowdsec restart или через GUI:\nServices → CrowdSec → Settings → Apply\nFirewall rules для блокировки исходящих подключений # По умолчанию CrowdSec в OPNsense блокирует входящие соединения от известных вредоносных IP-адресов. Однако это не защищает ситуацию, когда устройство внутри вашей сети само пытается обратиться к такому адресу.\nНапример, это может быть:\nзаражённый хост в локальной сети; вредоносный скрипт или контейнер; случайно запущенное подозрительное ПО. В таких случаях соединение будет разрешено, если отдельно не запретить исходящий трафик к известным плохим IP.\nДля этого в OPNsense рекомендуется использовать Floating Rules, которые позволяют применять правила сразу к нескольким интерфейсам (LAN/VLAN).\nСоздание Floating Rule # Перейдите в:\nFirewall → Rules → Floating\nНажмите Add (+) в правом верхнем углу.\nНастройте правило следующим образом:\nПараметр Значение Action Block Interface LAN (или нужные VLAN/интерфейсы) Direction In Protocol Any Destination crowdsec_blacklists Log Enabled Description Block access to CrowdSec blacklist IPv4 и IPv6 # Если в сети используется IPv6, необходимо создать отдельное правило для IPv6-трафика.\nOPNsense не всегда автоматически применяет одинаковые правила ко всем стекам (IPv4/IPv6), поэтому лучше разделить их явно:\nодно правило для IPv4 второе правило для IPv6 Применение правил # После создания правил нажмите:\nApply Changes\nС этого момента любые попытки изнутри сети обратиться к IP-адресам из CrowdSec blacklist будут блокироваться на уровне firewall.\nПрактический смысл # Эта настройка закрывает важный пробел:\nCrowdSec защищает входящий трафик (internet → LAN) Floating rules защищают исходящий трафик (LAN → internet) Вместе они позволяют не только ограничивать внешние атаки, но и снижать риск компрометации устройств внутри вашей сети.\nБлокировка известных вредоносных IP-адресов с помощью FireHOL # Даже при правильно настроенном межсетевом экране в журнале OPNsense можно заметить постоянные попытки подключения со стороны ботов, сканеров и других потенциально нежелательных узлов. Полностью исключить такой трафик невозможно, однако его можно значительно сократить, используя публичные списки IP-адресов, замеченных в различной вредоносной активности.\nОдним из наиболее популярных источников таких списков является FireHOL. Проект регулярно объединяет данные из различных Threat Intelligence-источников и публикует готовые списки IP-адресов, связанных с ботнетами, вредоносным программным обеспечением, серверами управления (C\u0026amp;C), сетевыми сканерами и другими угрозами.\nВ OPNsense такие списки можно подключить в виде URL-алиасов, после чего система будет автоматически загружать их и использовать при фильтрации трафика.\nСоздание алиаса FireHOL # Перейдите в Firewall → Aliases и нажмите Add.\nЗаполните поля следующим образом:\nПоле Значение Name Firehol Type URL (IPs) В поле Content добавьте ссылки на используемые блок-листы:\nhttps://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level1.netset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level2.netset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_level3.netset https://raw.githubusercontent.com/firehol/blocklist-ipsets/master/firehol_abusers_1d.netset После сохранения нажмите Apply, чтобы OPNsense загрузила содержимое списков.\nИсключение локальных сетей # Несмотря на то что списки FireHOL содержат только публичные IP-адреса, хорошей практикой считается исключение внутренних диапазонов сети из проверки.\nWarning Какой уровень FireHOL выбрать? FireHOL объединяет десятки различных источников информации об угрозах и предоставляет несколько уровней блокировки.\nfirehol_level1 - наиболее консервативный список. В него попадают IP-адреса с высокой репутацией угроз, поэтому риск ложных срабатываний минимален. Именно этот уровень можно рекомендовать большинству пользователей. firehol_level2 - содержит больше адресов и обеспечивает более агрессивную фильтрацию, однако вероятность блокировки легитимных ресурсов становится выше. firehol_level3 - максимально строгий уровень. Он объединяет большое количество источников и может вызывать ложные срабатывания, поэтому использовать его стоит только в том случае, если вы понимаете возможные последствия. firehol_abusers_1d - список IP-адресов, замеченных в подозрительной активности за последние сутки. Он постоянно обновляется и помогает оперативно блокировать новые источники атак. Для домашней сети или небольшой инфраструктуры чаще всего достаточно использовать firehol_level1. Если вы регулярно наблюдаете большое количество сканирований или попыток подбора паролей, можно дополнительно подключить firehol_abusers_1d. Уровни level2 и level3 лучше включать только после оценки возможных последствий и контроля журналов межсетевого экрана. Для этого создайте алиас со следующими параметрами:\nПоле Значение Name External Type Networks В качестве содержимого укажите:\n!10.0.0.0/8 !172.16.0.0/12 !192.168.0.0/16 !127.0.0.0/8 Затем создайте еще один алиас:\nПоле Значение Name Firehol_without_internal Type Network Group В него необходимо добавить алиасы External и Firehol.\nСоздание правила блокировки # Теперь остается создать правило межсетевого экрана.\nПерейдите в Firewall → Rules → WAN и добавьте новое правило со следующими параметрами:\nПоле Значение Action Block Interface WAN Direction In Protocol Any Source Firehol_without_internal Destination Any После сохранения нажмите Apply changes.\nТеперь все входящие соединения с IP-адресов, присутствующих в списках FireHOL, будут автоматически блокироваться еще до обработки другими правилами межсетевого экрана.\nАвтоматическое обновление списков # IP-адреса, используемые злоумышленниками, постоянно меняются, поэтому блок-листы необходимо регулярно обновлять.\nПерейдите в System → Settings → Cron и создайте новое задание со следующими параметрами:\nПоле Значение Enabled checked Minutes 0 Hours 0 Day of the month * Months * Days of the week * Command Update and reload firewall aliases После этого OPNsense будет ежедневно загружать актуальные версии списков FireHOL и автоматически применять изменения без вашего участия.\nGeoblock # Географическая блокировка (GeoIP) # Если ваши сервисы предназначены только для пользователей из определенных стран, имеет смысл ограничить доступ по географическому признаку. В OPNsense это реализуется с помощью GeoIP-алиасов, которые позволяют создавать правила межсетевого экрана на основе страны, к которой относится IP-адрес.\nНастройка базы GeoIP # Для работы GeoIP необходимо подключить базу данных MaxMind GeoLite2.\nСначала зарегистрируйтесь на сайте MaxMind и получите персональный лицензионный ключ. Для пользователей из России это может быть проблема, так как MaxMind удалила возможность регистрации для пользователей из России, но я думаю, что эту проблему вы решите.\nПосле этого перейдите в Firewall → Aliases → GeoIP settings и в поле URL укажите ссылку следующего вида, заменив your-license-key на полученный лицензионный ключ:\nhttps://download.maxmind.com/app/geoip_download?edition_id=GeoLite2-Country-CSV\u0026amp;license_key=your-license-key\u0026amp;suffix=zip Сохраните изменения.\nNote Лицензионные ключи MaxMind с конца 2023 года истекают каждые 90 дней, если их не подтверждать по почте. Если через несколько месяцев автообновление GeoIP-базы вдруг перестанет работать - в первую очередь проверьте, не протух ли ключ, а не ищите проблему в настройках OPNsense.\nБолее подробно можно почитать тут.\nСоздание GeoIP-алиасов # После подключения базы данных перейдите в Firewall → Aliases и создайте алиас со следующими параметрами:\nПоле Значение Name Geoblock Type GeoIP (IPv4, IPv6) Content Выберите страны, доступ из которых нужно заблокировать Если необходимо разрешить доступ из определенной страны, создайте еще один GeoIP-алиас. Например, для России:\nПоле Значение Name UK Type GeoIP (IPv4, IPv6) Content Russia Создание правил межсетевого экрана # Теперь необходимо создать соответствующие правила межсетевого экрана.\nПерейдите в Firewall → Rules → WAN и создайте правило блокировки:\nПоле Значение Action Block Interface WAN Direction In TCP/IP Version IPv4 + IPv6 Protocol Any Source Geoblock Destination Any Description Blocks specific countries Если требуется предоставить доступ к определенному сервису только из выбранной страны, создайте правило разрешения:\nПоле Значение Action Pass Interface WAN Direction In TCP/IP Version IPv4 + IPv6 Protocol TCP Source RU Destination WAN address Destination port 443 Description Whitelist RU on port 443 Важно. Правила межсетевого экрана в OPNsense обрабатываются сверху вниз. Поэтому правило Pass должно располагаться выше правила Block, иначе соединение будет заблокировано раньше, чем система дойдет до разрешающего правила.\nАвтоматическое обновление базы GeoIP # База MaxMind регулярно обновляется, поэтому рекомендуется настроить ее автоматическое обновление.\nПерейдите в System → Settings → Cron и создайте новое задание:\nПоле Значение Enabled ✓ Minutes 0 Hours 0 Day of month * Months * Day of week * Command Update and reload firewall aliases После этого OPNsense будет ежедневно загружать актуальную базу GeoIP и автоматически обновлять все алиасы, использующие географическую фильтрацию.\nБлокировка рекламы # Блокировка рекламы и вредоносных доменов # Одним из преимуществ Unbound DNS является встроенная поддержка DNS Block Lists (DNSBL). Эта технология позволяет блокировать рекламу, трекеры, вредоносные домены и фишинговые сайты еще на этапе DNS-разрешения, не позволяя клиентам сети установить соединение.\nПеред началом убедитесь, что служба Unbound DNS включена.\nПерейдите в:\nServices → Unbound DNS → General\nи активируйте параметр Enable Unbound.\nПерейдите в:\nServices → Unbound DNS → Blocklist\nВключите DNSBL и выберите списки блокировки.\nПараметр Значение Enable ✓ Type of DNSBL Toggle preferred lists Для начала рекомендуется использовать следующие списки:\nAbuse.ch OISD AdAway AdGuard Blocklist.site Если после включения блокировок некоторые сайты или сервисы перестанут работать, необходимые домены можно добавить в поле Whitelist Domains.\nПо мере необходимости можно подключать дополнительные списки, однако не стоит включать сразу все доступные источники. Это усложнит поиск причины возможных ложных срабатываний.\nАвтоматическое обновление DNS Block Lists # Чтобы списки блокировки всегда оставались актуальными, рекомендуется настроить их ежедневное обновление.\nПерейдите в:\nSystem → Settings → Cron\nСоздайте новое задание со следующими параметрами:\nПараметр Значение Minutes 0 Hours 0 Day of Month * Months * Day of Week * Command Update Unbound DNSBLs Description Update Unbound BLs После этого OPNsense будет автоматически обновлять DNS Block Lists каждый день в 00:00.\nNetFlow и Insight # NetFlow в OPNsense используется для сбора информации о сетевом трафике. Он позволяет понять, какие устройства и сервисы создают нагрузку, в какое время достигаются пики использования сети и как именно маршрутизируется трафик.\nМодуль Insight дополняет NetFlow визуальной аналитикой и отчетами. В нем доступны графики, статистика по интерфейсам, а также экспорт данных в CSV для дальнейшего анализа в таблицах или внешних инструментах.\nНастройка NetFlow # Перейдите в Reporting → NetFlow и настройте параметры следующим образом:\nОсновные параметры # Параметр Значение Listening interfaces LAN, WAN, все_другие_интерфесы_которые_хотите WAN interfaces WAN Capture local Enabled Version v9 Destinations 127.0.0.1:2056 После применения настроек OPNsense начнет собирать статистику по всем указанным интерфейсам и отправлять данные в локальный collector.\nПросмотр статистики в Insight # После активации NetFlow данные становятся доступны в модуле анализа.\nПерейдите в:\nReporting → Insight\nЗдесь можно:\nпросматривать графики загрузки сети;\nанализировать распределение трафика по интерфейсам;\nотслеживать пики нагрузки;\nвыгружать данные в CSV для дальнейшего анализа.\nInsight фактически превращает OPNsense в инструмент базовой сетевой аналитики, позволяя видеть не только “что не работает”, но и “что и как именно используется в сети”.\nНастройки отчетности (Reporting Settings) # OPNsense собирает статистику по системе и сетевым интерфейсам с помощью встроенного механизма графиков (RRD - Round-Robin Database). Это позволяет хранить исторические данные о нагрузке и просматривать их в виде графиков прямо в веб-интерфейсе.\nUnbound DNS reporting # Если в системе используется DNS-резолвер Unbound, можно включить сбор статистики по DNS-запросам.\nПараметр Значение Statistics Enabled После включения OPNsense начнет собирать данные о DNS-запросах локальной сети. Это позволяет анализировать, какие домены запрашиваются чаще всего и как ведут себя клиенты в сети.\nReporting Database (RRD) # Следующий блок отвечает за хранение и отображение графиков производительности системы.\nПараметр Значение Round-Robin-Database Enabled RRD используется для построения графиков загрузки CPU, памяти, сетевых интерфейсов и других системных метрик. Данные хранятся в сжатом виде и автоматически перезаписываются по мере заполнения базы.\nПосле изменения настроек графиков может потребоваться до 1 минуты, прежде чем новые данные начнут отображаться корректно.\nSplit DNS # Что такое Split DNS кратко # Термин Split DNS обычно переводят на русский как «разделённый DNS» или «разделённая система доменных имён».\nСмысл концепции такой: один и тот же домен (например, stilicho.ru) разрешается по-разному в зависимости от того, с какой сети обращается клиент: внутренней (LAN) или внешней (Интернет).\nПримеры перевода и использования:\nSplit DNS → Разделённый DNS Split-horizon DNS → иногда тоже Разделённый DNS или DNS с разделённым горизонтом Раздельный DNS позволяет давать разные ответы на DNS-запросы для внутренних и внешних пользователей, поэтому локальным запросам к вашему серверу не придется проходить через маршрутизатор. Это имеет несколько преимуществ:\nБыстрее, так как не нужно проходить через маршрутизатор. Обратный прокси-сервер может легко различать внутренние и внешние запросы, разрешая/запрещая их, поскольку NAT отсутствует. При отсутствии интернета все продолжает работать. Система продолжает работать, даже если DNS-сервер верхнего уровня (ваш интернет-провайдер/Google/OpenDNS и т. д.) недоступен. Требования # Внутренний обратный прокси-сервер, прослушивающий порт 80/443. Внутренний DNS-резолвер, поддерживающий перезапись или размещение полных DNS-зон. Популярные конфигурации DNS # В этом примере предполагается, что domain.com - ваш домен и 10.10.10.10 - ваш обратный прокси-сервер.\nПерейдите в раздел Services \u0026gt; Unbound DNS \u0026gt; Overrides \u0026gt; Host Overrides \u0026gt; Добавить:\nHost: * Domain: stilicho.ru Type: A or AAAA IP: 10.10.10.10 Заключение # На этом базовая настройка OPNsense завершена (хотя какая она базовая, правда?) и у нас есть рабочий firewall с сегментацией сети и настройками безопасностью выше среднего.\nДальше всё зависит от твоей инфраструктуры и желания продолжить настройку дальше, например, можно и нужно добавить IDS/IPS.\nВажно понимать, что OPNsense - это не бытовой роутер, который “plug and play”, а инструмент, который раскрывается постепенно. Чем глубже ты его интегрируешь в свою сеть, тем больше контроля получаешь над трафиком и безопасностью.\n","date":"1 July 2026","externalUrl":null,"permalink":"/posts/opnsense-26.1/","section":"Posts","summary":"Практический гайд по OPNsense 26.1 - установка на железо, настройка firewall, GeoIP, FireHOL и CrowdSec, а также мониторинг сети и защита домашней лаборатории.","title":"OPNsense 26.1: установка и настройка с нуля","type":"posts"},{"content":"","date":"1 July 2026","externalUrl":null,"permalink":"/series/%D1%80%D0%B0%D0%B1%D0%BE%D1%82%D0%B0-%D1%81-opnsense/","section":"Series","summary":"","title":"Работа С Opnsense","type":"series"},{"content":"","date":"May 31, 2026","externalUrl":null,"permalink":"/en/tags/backup/","section":"Tags","summary":"","title":"Backup","type":"tags"},{"content":"","date":"May 31, 2026","externalUrl":null,"permalink":"/en/tags/pbs/","section":"Tags","summary":"","title":"PBS","type":"tags"},{"content":"","date":"May 31, 2026","externalUrl":null,"permalink":"/en/categories/proxmox/","section":"Categories","summary":"","title":"Proxmox","type":"categories"},{"content":"A series of articles about Proxmox Virtual Environment - a powerful platform for virtualization and containerization. We cover installation, storage configuration, clustering, migrations, network configuration, SDN, firewall, as well as automation and integration with Terraform.\n","date":"May 31, 2026","externalUrl":null,"permalink":"/en/posts/proxmox/","section":"Posts","summary":"A series of articles about Proxmox Virtual Environment - a powerful platform for virtualization and containerization. We cover installation, storage configuration, clustering, migrations, network configuration, SDN, firewall, as well as automation and integration with Terraform.","title":"Proxmox","type":"posts"},{"content":"","date":"May 31, 2026","externalUrl":null,"permalink":"/en/series/proxmox/","section":"Series","summary":"","title":"Proxmox","type":"series"},{"content":"","date":"May 31, 2026","externalUrl":null,"permalink":"/en/tags/proxmox/","section":"Tags","summary":"","title":"Proxmox","type":"tags"},{"content":" Foreword # Frankly, I wasn\u0026rsquo;t planning to record a new video about Proxmox Backup Server, nor to write a full article. But I made the mistake of quickly upgrading Proxmox VE to the new kernel version 7.0.0.3.\nAs a result, the system stopped booting and consistently went into a kernel panic with an unpleasant pink screen. Rolling back to the previous kernel version didn\u0026rsquo;t work in my case.\nA search on the official Proxmox forum showed that the problem wasn\u0026rsquo;t isolated but widespread. In the end, I had to reinstall the node from scratch.\nFor an average user, this could mean losing all the information stored in the virtual machines or LXC containers. However, I use Proxmox Backup Server, and the backups are stored on a NAS, so I got off relatively lightly.\nI had to redeploy the node, install PBS, connect the old datastore, and restore everything from backups.\nAfter that, I shared the situation on my Telegram channel, warned about the problems with the fresh Proxmox VE kernel build, and reminded everyone about the importance of backups. In response, I was offered to go somewhere to record a fresh overview video about restoring a node.\nAlthough I already have a video about PBS on my channel, it\u0026rsquo;s noticeably outdated by industry standards. So I decided to update the material.\nIn this article, I won\u0026rsquo;t just cover setting up Proxmox Backup Server, but also show my real-world scenario: creating two datastores - one for \u0026ldquo;hot\u0026rdquo; and one for \u0026ldquo;cold\u0026rdquo; backups.\nIntroduction # Backup is one of the key tasks both in a home lab (homelab) and in corporate infrastructure. Losing a virtual machine, disk corruption, or a failed update can have serious consequences if a backup system isn\u0026rsquo;t set up in advance.\nTo address this, the Proxmox team developed Proxmox Backup Server (PBS) - a specialized system for storing backups of virtual machines, containers, and physical servers.\nPBS supports:\ndata deduplication incremental backups efficient compression convenient integration with Proxmox VE This allows you to significantly save disk space and speed up backup and restore processes.\nProxmox Backup Server 4.x adds:\nsupport for S3-compatible storage improved sync jobs extended capabilities for working with namespaces and datastores base system update to Debian 13 In this article, we\u0026rsquo;ll install Proxmox Backup Server 4.2, set up storage, connect it to Proxmox VE, and perform our first virtual machine backup.\nWhat is a Datastore in Proxmox Backup Server # General description # A Datastore in Proxmox Backup Server (PBS) is the main backup storage. You can think of it as a folder or logical container in which PBS stores all backup data, indexes, metadata, and deduplication information.\nWhat\u0026rsquo;s inside a Datastore # When creating a Datastore, PBS uses the specified directory, for example:\n/mnt/backup/pbs-datastore Inside, a directory structure is created:\npbs-datastore/ ├── .chunks/ ├── vm/ ├── ct/ ├── host/ └── .lock The Datastore holds:\nVirtual machine backups LXC container backups Physical server backups via PBS Client Deduplicated data chunks Indexes and metadata How deduplication works # PBS splits data into small blocks (chunks) and stores only new or changed data.\nExample:\nThe first backup of a virtual machine takes up 100 GB. The next day, only 2 GB of data changed. PBS will only store the new chunks, totaling 2 GB. As a result, a Datastore can contain many backups while taking up significantly less space thanks to deduplication.\nMultiple Datastores on a single PBS # You can create several Datastores on a single PBS server for different purposes.\nExamples:\nDatastore Purpose local-ssd Fast daily backups hdd-backup Long-term storage offsite Replication to a remote site Example configuration:\nDatastore: fast-backup Path: /mnt/ssd/pbs Datastore: archive Path: /mnt/hdd/pbs Each Datastore has its own settings:\nRetention policies (Prune) Backup verification (Verify) Synchronization (Sync) Access permissions Read/write speed limits Recommendations # Use a reliable Linux file system (for example, ZFS) Don\u0026rsquo;t modify Datastore contents manually Remove old backups via Prune jobs Regularly run Verify to check data integrity Monitor disk health and free space Important # Manually deleting Datastore files can corrupt backups and result in data loss. Losing or corrupting a Datastore makes all backups stored in it unavailable. Analogy # If you think of PBS as a library:\nComponent Analogy PBS Server Library Datastore Book warehouse Backup Book Chunk Page of the book Deduplication Storing identical pages only once In the video, I\u0026rsquo;ll create only two datastores:\nfast, daily copies long-term data, which I\u0026rsquo;ll store on my TrueNAS System requirements # Before starting the installation of Proxmox Backup Server 4.2, you need to prepare a separate server or virtual machine. Although PBS can run even on fairly modest hardware, it\u0026rsquo;s recommended to estimate the volume of backups and the number of protected systems in advance. For a home environment, the first factor is of course the important one.\nRight now, in the international YouTube segment, for some reason it\u0026rsquo;s popular to install PBS in an LXC container. I don\u0026rsquo;t like this approach, because such an installation requires either a privileged container or certain complications with mounting disks. At the same time, installing it in a virtual machine (in case you can\u0026rsquo;t dedicate a separate server/mini-PC) doesn\u0026rsquo;t add any noticeable overhead in a homelab scenario. PBS is a fairly lightweight solution.\nTo perform the installation you\u0026rsquo;ll need:\nMinimum requirements # 64-bit processor with virtualization support\n2 CPU cores\n2 GB of RAM\n8 GB of disk space for the system\nA separate disk or partition for storing backups\nNetwork connection of at least 1 Gbit/s\nRecommended requirements # 4 or more CPU cores\n8-16 GB of RAM\nSSD for the system partition\nA separate SSD or HDD array for storing backups\nZFS file system for the datastore\n2.5 Gbit/s network connection or higher when working with a large number of virtual machines\nIronically, finding a server meeting only the minimum requirements is practically impossible in 2026. At the same time, if we\u0026rsquo;re talking about a home environment, the minimum requirements are sufficient for continuous operation. The reason is that the system load only occurs during those short intervals when the system is performing backups and comparing chunks. As you understand, in a home environment this happens at best once a day, and the whole process fits within an hour.\nTest bench # For this article and video, Proxmox Backup Server 4.2 is installed on a Lenovo ThinkCentre M720q with the following specifications:\nParameter Value CPU Intel Core i5-8400T RAM 16 GB System disk 256 GB NVMe Backup disk 500 GB SSD Network 1 Gbit/s Such a configuration isn\u0026rsquo;t just more than enough for a home lab and backing up several virtual machines and LXC containers, it\u0026rsquo;s actually overkill.\nIt\u0026rsquo;s recommended to use a separate disk or a ZFS pool for storing backups. This allows you to make the most efficient use of built-in data deduplication and protect the system from losing backups if the system disk fails.\nInstalling Proxmox Backup Server # Installing PBS shouldn\u0026rsquo;t cause any difficulties - the installer interface is identical to PVE.\nYou agree to the license agreement,\nChoose the disk or array where the operating system will be installed, as well as the file system.\nSet the root user\u0026rsquo;s password, and specify the email address where the system will send notifications. Note that simply specifying an email address isn\u0026rsquo;t enough - you\u0026rsquo;ll later need to provide the values obtained from your email provider.\nNext, choose the primary network interface (in case you have more than one), the hostname (I always later install a proper SSL certificate from Let\u0026rsquo;s Encrypt), and the network values for the host and gateway.\nInitial configuration # We\u0026rsquo;re greeted with an interface fairly similar to PVE, which makes sense. Unification is an important point here. First, we go to the Administration \u0026gt; Repositories section.\nand connect the free repositories, while deactivating the paid repositories.\nafter that, we go to the neighboring Updates menu and update the package database. If necessary, restart the PBS instance.\nPreparing disk space and configuring the Datastore # In our case, we already have a share (a dataset in TrueNAS) that already served as a datastore at some point. We also have a separate 512 GB SSD disk for daily backups. Let\u0026rsquo;s start with preparing this disk. In the Storage \u0026gt; Disks section we see the list of connected disks. In my case, the system is installed on an NVMe disk. The SSD disk is recognized in the system as /dev/sda.\nFirst of all, we need to partition it. In the disks section, select the disk we need and choose Initialized Disk with GPT.\nAfter that, go to the command line menu (Shell). Install the parted utility with the command\napt install parted create a partition\nparted /dev/sda -- mkpart primary ext4 0% 100% resulting in:\n/dev/sda1 Format the partition.\nFor PBS, the following are usually used:\next4 - simple and reliable xfs - good for large backup storage zfs - if you need RAID/compression/snapshots The simplest option:\nmkfs.ext4 /dev/sda1 Write down the resulting UUID somewhere, you\u0026rsquo;ll need it later when mounting the new datastore for daily backups. However, if for some reason the UUID gets lost, you can always find it out with the command\nblkid /dev/sda1 First, create two folders that will serve as directories for storing data:\nlenovo - daily backups truenas - long-term backups Now let\u0026rsquo;s edit the fstab file\nnano /etc/fstab this way we\u0026rsquo;ve mounted the corresponding partition and remote share to specific directories. Save the changes with Ctrl+S, exit with Ctrl+X.\nEnter the command\nmount -a If everything is fine and we haven\u0026rsquo;t made any mistakes, the system will suggest reloading the daemon with the command\nsystemctl daemon-reload Creating the datastore # After we\u0026rsquo;ve mounted the shares and partitions we need into the corresponding directories, we proceed to creating the datastore. As I mentioned above, we\u0026rsquo;ll have two:\na local one for daily backups. Let\u0026rsquo;s call it lenovo. a remote one for long-term storage, located on an NFS share on my TrueNAS. Go to the Datastore \u0026gt; Add Datastore section.\nSet the datastore name, choose its type. For the path, we need to enter an absolute path. We won\u0026rsquo;t touch the GC Schedule and Prune Schedule menus for now. We\u0026rsquo;ll configure that part later.\nSince I also need to connect an already existing datastore, I go into the advanced menu and check the reuse existing datastore option. In Proxmox Backup Server 4.2, the \u0026ldquo;Reuse existing datastore\u0026rdquo; option means:\nuse an already existing folder with backups as a datastore, without creating it from scratch.\nRepeat the same steps, but for the new datastore.\nSince this is a new datastore, it\u0026rsquo;s enough to give it a name and specify the storage path.\nAs a result, we\u0026rsquo;ll see the created datastores in the control panel, along with data on used storage volume, a list of jobs, and a summary.\nConnecting the created datastores to Proxmox Virtual Environment # In Proxmox VE, you can\u0026rsquo;t connect a datastore directly as a disk.\nYou connect the PBS server, and the datastore is selected inside it.\nMake sure the datastore is created in PBS # On the PBS side, the datastores we need are already created.\nAdding PBS to Proxmox VE # In the PVE web interface:\nDatastore \u0026gt; Storage \u0026gt; Add \u0026gt; Proxmox Backup Server\nFilling in the parameters # Server # IP or DNS name of PBS:\n192.168.1.10 Datastore # This is NOT a path in the file system.\nSpecify the datastore name from PBS:\ntruenas Username # It\u0026rsquo;s recommended to use a separate user, but you can use:\nroot@pam or:\nbackup@pbs backup is the name of the user created in PBS.\nPassword # The password of the PBS user.\nFingerprint # We get this from PBS:\nDashboard \u0026gt; Show Fingerprint\nConnection result # After adding it in PVE, the storage will appear:\nNow you can use it to back up VMs and CTs.\nHow PVE works together with PBS # PBS stores data and deduplicates it PVE sends backups over the network The Datastore inside PBS manages the data For this, we first need to configure the backup schedule and where backups are stored (by default, PVE stores backups on its own LVM partition).\nIn PVE, go to the Datacenter section.\nDatacenter \u0026gt; Backup\nand configure the backup schedule, the list of items to back up, and where we\u0026rsquo;ll save the backups.\nNow every 24 hours PVE will create copies of the selected resources and save them to our lenovo storage, which is the datastore for daily backups in PBS.\nConfiguring backup handling in PBS # Go to the corresponding section in the datastore menu in PBS.\nConfiguring the Prune Job, Garbage Collection, and Verification Job in Proxmox Backup Server # Prune Job (retention policy) # The Prune Job is responsible for removing old snapshots according to a defined retention policy. It\u0026rsquo;s important to understand that prune only removes references to backup snapshots, not the physical data right away.\nConfiguring the Prune Job # Schedule\nYou can use a simple schedule or cron:\ndaily 0 2 * * *\nRetention policy (keep options) # As an example of a reasonably balanced policy:\nkeep-daily: 7 keep-weekly: 4 keep-monthly: 6\nThis means:\nkeep the last 7 days the last 4 weeks the last 6 months Warning Prune doesn\u0026rsquo;t free up disk space immediately, since the data may remain in chunks until Garbage Collection runs.\nGarbage Collection (data cleanup) # Garbage Collection removes physically unused chunks left over after pruning.\nHow it works\nPBS uses deduplication, so a single chunk can be used across multiple backups. After pruning, references are removed, but the data itself remains until GC runs.\nGC goes through and removes:\nunused chunks stale data with no references Configuring Garbage Collection # Datastore → Garbage Collection → Add\nExample of a recommended schedule\nweekly 0 3 * * 0 (every Sunday night)\nWarning requires high disk load better to run at night can take a long time on large datastores Verification Job (integrity check) # The Verification Job checks data integrity and detects corrupted chunks.\nWhat it checks:\ncorrupted blocks silent corruption correctness of the chunk structure Why this matters:\nEven SSDs and HDDs can:\ncorrupt data without any OS errors suffer hidden degradation Verification helps detect this in advance.\nConfiguring the Verification Job # Datastore → Verification Jobs → Add\nSchedule option\nHome lab: monthly Production: weekly or bi-weekly\nThe correct order of tasks # It\u0026rsquo;s very important to follow the correct order of tasks:\nPrune Job Garbage Collection Verification Job Common mistakes # Only Prune without GC → space isn\u0026rsquo;t freed Too frequent GC → unnecessary load on the SSD No Verification → risk of silent data corruption Summary # In the end, the three tasks work together:\nPrune manages the retention period GC frees up disk space Verification protects against data corruption\nProperly configuring these processes ensures stability, space savings, and reliability of the backup system.\nConfiguring synchronization between datastores # Sync jobs are configured to fetch the contents of a datastore from a remote server (Remote) and copy it into a local datastore.\nYou can manage sync jobs through the web interface - in the Sync Jobs tab of the Datastore panel, or inside the Datastore itself. You can also manage them via the proxmox-backup-manager sync-job command.\nThe sync job configuration is stored in the file:\n/etc/proxmox-backup/sync.cfg To create a new sync job, click the Add button in the GUI or use the create command in the CLI.\nAfter creating a sync job, you can:\nrun it manually through the GUI run it via the CLI with the run command or set a schedule (see Calendar Events) so it runs regularly In my case, I want the copies from the lenovo datastore, where we store daily copies, to sync with the truenas datastore, where the long-term storage copies will be kept.\nNote as you understand, the backup schedules for different datastores will differ\nConclusions # Setting up Proxmox Backup Server isn\u0026rsquo;t just about connecting a disk and creating storage - it\u0026rsquo;s a full-fledged system for managing the lifecycle of backups.\nA properly configured combination of datastore + prune + garbage collection + verification + sync job provides a complete set of mechanisms for reliable, scalable backups.\nKey advantages of the system # Controlled data retention (Prune Jobs) Let you set a retention policy and prevent the disk from filling up. Freeing disk space (Garbage Collection) Removes unused chunk data left after snapshots are deleted. Integrity checking (Verification Jobs) Detects data corruption and silent corruption before it becomes a problem. Synchronization between servers (Sync Jobs) Allows copying a datastore from a remote PBS to a local or backup server. This is used for: backup replication offsite storage protection against loss of the primary server Process automation All tasks can run on a schedule without manual intervention. When properly configured, Proxmox Backup Server becomes a full-fledged, production-level backup system that:\nmakes efficient use of disk space ensures high storage reliability allows you to build distributed and fault-tolerant setups minimizes manual maintenance It\u0026rsquo;s precisely the combination of prune, GC, verification, and sync that turns PBS into more than just storage - it becomes a complete data lifecycle management system.\n","date":"May 31, 2026","externalUrl":null,"permalink":"/en/posts/proxmox-backup-server-4-2-installation-guide/","section":"Posts","summary":"A complete guide to installing and configuring Proxmox Backup Server 4.2.0 for building a reliable backup system for Proxmox VE virtual machines and containers.","title":"Proxmox Backup Server 4.2.0: installation, configuration, and Proxmox VE backup","type":"posts"},{"content":"","date":"30 May 2026","externalUrl":null,"permalink":"/tags/dockhand/","section":"Tags","summary":"","title":"Dockhand","type":"tags"},{"content":" Dockhand - простой веб-интерфейс для управления Docker # Если ты устал от постоянной работы в терминале, тебя не устраивает Portainer и ты хочешь быстро управлять контейнерами через браузер - Dockhand может стать отличным решением.\nМного их - заменителей Portainer, я видел. Но все они так и дотягивались до его функционала.\nФактически реальных конкурентов у Portainer не так и много:\nKomodo - полностью open source решение, но разработчики сразу целятся в enterprise сектор.\nArcane - лично не пробовал, поэтому мнения не имею.\nDockge - но это не полноценная замена конечно. Тут целевая группа исключительно хоумлабберы и функционал которого несколько упрощен, но только если сравнивать с решениями для профессиональной среды.\nИ герой сегодняшнего обзора\nDockhand - это лёгкий и минималистичный веб-интерфейс для Docker, который отлично вписывается в любой homelab и особенно хорошо работает в связке с обратным прокси Traefik.\nВозможности Dockhand # Dockhand - это не просто веб-интерфейс для Docker, а полноценный инструмент управления контейнерной инфраструктурой с упором на удобство, автоматизацию и безопасность.\nНиже - обзор только некоторые возможностей.\nУправление контейнерами # Dockhand предоставляет полный контроль над контейнерами без необходимости использовать CLI:\nЗапуск, остановка, перезапуск и удаление контейнеров\nСоздание контейнеров с расширенной конфигурацией\nПросмотр процессов внутри контейнера\nДоступ к переменным окружения (env vars)\nВстроенный веб-терминал (без необходимости SSH)\nПросмотр и передача файлов внутри контейнера\nЭто делает Dockhand отличной заменой базовым CLI-операциям.\nDocker Compose и Stacks # Работа с multi-container приложениями реализована максимально удобно:\nПоддержка Docker Compose и стеков. Причем можно управлять и стеками, созданными за пределами приложения (как этого добиться я рассказываю в видео)\nВизуальный редактор Compose (без необходимости писать YAML вручную)\nДеплой стеков напрямую из Git-репозиториев\nАвтоматическая синхронизация при push (через webhooks)\nПовторная загрузка образов (re-pull) и принудительный redeploy\nИмпорт проектов из других менеджеров контейнеров\nПланировщик обновлений и деплоев\nОтличный вариант для GitOps-подхода в homelab.\nВозможности по мониторингу (Observability) # Dockhand даёт полный контроль над состоянием контейнеров в реальном времени:\nLive-метрики CPU и памяти для каждого контейнера\nПотоковое отображение логов в реальном времени (с ANSI-цветами)\nЖурнал активности контейнеров\nМониторинг использования диска\nУведомления через email и webhooks\nВсё это без необходимости настраивать Prometheus и Grafana.\nБезопасность # Dockhand предлагает мощные встроенные механизмы безопасности:\nПоддержка OIDC / SSO (любой провайдер)\nИнтеграция с LDAP / Active Directory (платная функция)\nRole-Based Access Control (RBAC) (платная функция)\nСканирование уязвимостей (Grype / Trivy)\nМожно легко встроить в существующую IAM-инфраструктуру.\nMulti-host управление # Dockhand не ограничивается одним Docker-хостом:\nПодключение через локальный Docker socket\nПоддержка удалённых Docker-хостов (TCP + TLS)\nHawser-агент для обхода NAT и firewall\nБыстрое переключение между окружениями\nОтдельные dashboard-плитки для каждого окружения\nУдобно для управления несколькими серверами из одного интерфейса.\nКастомизация интерфейса # Dockhand можно адаптировать под себя:\nСветлая и тёмная темы\nНастраиваемый размер шрифта\nУправление колонками (скрытие, отображение, порядок)\nИзменяемые размеры dashboard-плиток\nСохранение пользовательских настроек\nИнтерфейс реально гибкий, а не “как есть”.\nПрозрачность и лицензия # Dockhand делает ставку на открытость:\nПолный исходный код доступен на GitHub\nКод полностью открыт для изучения\nПереход на Apache 2.0 запланирован в 2029 году\nПодход: «Доверяй, но проверяй» - и здесь это возможно\nСистемные требования # System requirements # Компонент Требования Docker Engine 20.10 или новее Docker API 1.41 или новее Память 512 MB минимум, 1 GB рекомендовано Браузер Chrome, Firefox, Safari, Edge База данных SQLite (по умолчанию) или PostgreSQL 14+ Важно перед установкой # Warning Dockhand использует:\n/var/run/docker.sock Это значит, что:\nконтейнер получает полный доступ к Docker фактически - root-доступ к системе Рекомендации:\nиспользовать только в доверенной сети закрывать доступ через reverse proxy (например Traefik + auth) Вариант docker compose файла, который используется в видео ролике # services: # Секция описания сервисов (контейнеров) dockhand: # Имя сервиса (используется внутри compose) image: fnsys/dockhand:latest # Docker-образ (берётся из Docker Hub, тег latest = последняя версия) container_name: dockhand # Явное имя контейнера (удобно для управления и логов) restart: unless-stopped # Политика перезапуска (перезапускать всегда, кроме ручной остановки) #ports: # Проброс портов (сейчас отключён) # - 3000:3000 # Хост:контейнер (если включить - доступ напрямую без Traefik) volumes: # Монтирование томов (данные и сокеты) - /var/run/docker.sock:/var/run/docker.sock # Доступ к Docker API (контейнер управляет Docker ⚠️) - /home/stilicho/docker/dockhand/data:/app/data # Локальная папка для хранения данных приложения networks: proxy: # Подключение к сети proxy (используется Traefik) labels: - \u0026#34;traefik.enable=true\u0026#34; # Включаем Traefik для этого контейнера # ========================= # HTTP ROUTER (порт 80) # ========================= - \u0026#34;traefik.http.routers.dockhand.entrypoints=web\u0026#34; # Traefik слушает входящий трафик на entrypoint \u0026#34;web\u0026#34; (обычно :80) # сюда попадает http://dockhand.stilicho.ru - \u0026#34;traefik.http.routers.dockhand.rule=Host(`dockhand.stilicho.ru`)\u0026#34; # Правило: если Host совпадает - используем этот router # Traefik сравнивает заголовок Host - \u0026#34;traefik.http.routers.dockhand.middlewares=dockhand-https-redirect\u0026#34; # Применяем middleware (редирект на HTTPS) # ДО проксирования в контейнер - \u0026#34;traefik.http.middlewares.dockhand-https-redirect.redirectscheme.scheme=https\u0026#34; # Сам middleware: # Traefik НЕ отправляет запрос в контейнер # он сразу отвечает клиенту: # 301 Redirect → https://dockhand.stilicho.ru # ========================= # HTTPS ROUTER (порт 443) # ========================= - \u0026#34;traefik.http.routers.dockhand-secure.entrypoints=websecure\u0026#34; # Входящий HTTPS трафик (обычно порт 443) - \u0026#34;traefik.http.routers.dockhand-secure.rule=Host(`dockhand.stilicho.ru`)\u0026#34; # То же правило по домену - \u0026#34;traefik.http.routers.dockhand-secure.tls=true\u0026#34; # Включаем TLS: # Traefik завершает SSL (TLS termination) # расшифровывает HTTPS → дальше работает как HTTP - \u0026#34;traefik.http.routers.dockhand-secure.service=dockhand\u0026#34; # Указываем, в какой service отправлять трафик # router → service связка # ========================= # SERVICE (куда идёт трафик) # ========================= - \u0026#34;traefik.http.services.dockhand.loadbalancer.server.port=3000\u0026#34; # Ключевая строка: # Traefik берёт IP контейнера в сети proxy # и делает запрос: # http://dockhand:3000 (внутри Docker-сети) # НЕ через localhost и НЕ через ports # ========================= # СЕТЬ # ========================= - \u0026#34;traefik.docker.network=proxy\u0026#34; # Указываем, в какой сети искать контейнер # важно, если контейнер в нескольких сетях # Traefik возьмёт IP именно из сети proxy # Описание сетей networks: proxy: external: true # Сеть уже существует (создана отдельно, например для Traefik) Я использую встроенную базу данных SQlite3, но приложение можно использовать и Postgres.\nБолее детально с вариантами установки приложения можно ознакомиться на родном сайте\nПервый запуск # После старта контейнера и перехода по поддоменному имени я был неприятно удивлен отсутствием меню первичной регистрации пользователя. С моей точки зрения это не самое оптимальное решение. Все-таки лучше принудительно заставлять беспечных пользователей создавать первоначального пользователя. Будем надеяться, что в последующем разработчики такую функцию реализуют.\nВ итоге нас встречает пустая панель, потому что мы еще не подключили наше первое окружение (environment).\nПанель управления (Dashboard) # Панель управления Dockhand предоставляет наглядный обзор всех ваших Docker-окружений в реальном времени. Интерфейс построен вокруг плиток (tiles), каждая из которых представляет отдельное окружение.\nПлитки можно:\nизменять по размеру перемещать по экрану настраивать под свой рабочий процесс Это позволяет адаптировать интерфейс под конкретные задачи и приоритеты.\nПлитки окружений (Environment Tiles) # Каждое Docker-окружение отображается в виде отдельной плитки с ключевой информацией:\nОкружение (Enviroments) # Название окружения Иконка Статус подключения Позволяет сразу понять, доступно ли окружение, что очень удобно на мой взгляд.\nКонтейнеры (Containers) # Количество запущенных контейнеров Количество остановленных контейнеров Общее количество контейнеров Позволяет быстро контролировать состояния инфраструктуры.\nВ разделе контейнеры вы сможете мгновенно оценить количество контейнеров, мх состояние, здоровье и количество потребляемых ресурсов. Это позволяет мгновенно оценить нагрузку на систему, что тоже очень полезно.\nСостояние (Health Status) # Предупреждения о проблемах Контейнеры в состоянии: unhealthy restarting Помогает быстро выявить сбои и нестабильные сервисы.\nDockhand позволяет проверять обновлений контейнеров в репозиториях, что, с моей точки зрения, \u0026ldquo;киллер фича\u0026rdquo;, позволяет, например, заменить мне приложение Diun. Вы даже можете настроить авто обновление контейнеров. Последнее - совсем небезопасная функция на мой взгляд, так как может привести к установке контейнеров с багами, которые могут повлечь за собой неработоспособность системы. Лучше все-таки сначала читать сhangelog. Поэтому, как мне кажется, узнавать о наличии обновлений - это очень удобно, а вот авто обновление уже на любителя.\nСканирование уязвимостей. # В Dockhand встроена функция для проверки уязвимостей контейнеров. На бумаге звучит это очень привлекательно, но по факту данная функция совершенно бесполезна. Встроенные инструменты всегда найдут уязвимости (это может быть предметом отдельной статьи), что, во-первых, приведет к панике у неофитов, а, во-вторых, приведет к блокировке работы контейнера системой. Хотя по факту это будет абсолютно здоровый покойник контейнер.\nВ заголовке каждой плитки отображаются индикаторы состояния:\nФото приложения # Итог # Панель управления Dockhand - это:\nПолный обзор всех окружений в одном месте Быстрая диагностика проблем Удобная визуализация нагрузки и активности Гибкая настройка интерфейса И как итог, - Dockhand отличная замена Portainer в домашнем окружении и отличный выбор, если тебе нужен баланс между простотой и функциональностью.\n","date":"30 May 2026","externalUrl":null,"permalink":"/posts/dockhand-docker-web-ui/","section":"Posts","summary":"Полное руководство по установке и настройке Dockhand - простого и удобного веб-интерфейса для управления Docker-контейнерами в homelab и production.","title":"Dockhand: веб-интерфейс для Docker с интеграцией Traefik","type":"posts"},{"content":"","date":"22 May 2026","externalUrl":null,"permalink":"/tags/netbird/","section":"Tags","summary":"","title":"Netbird","type":"tags"},{"content":"В случае если вам понравилась эта статья, то можете поддержать автора, став спонсором на Boosty.\nЕсли вы думаете, что NetBird - это просто ещё одно VPN приложение, которое может объединять ваши устройства в mesh-сеть, то … частично, да, вы правы.\nНо на практике - это гораздо более гибкий инструмент, который закрывает сразу несколько задач: приватная сеть, доступ к ресурсам и теперь ещё и публикация сервисов наружу.\nПредисловие # В homelab всё обычно начинается одинаково:\nСначала ты поднимаешь сервисы локально - всё работает идеально.\nПотом появляется желание зайти к ним извне. И тут начинается: проброс портов, NAT, firewall, динамический DNS, домены, HTTPS и постоянная паранойя «а всё ли я закрыл»?\nДальше - больше: появляется VPN (речь не про обход блокировок, товарищ майор, а про безопасность). Но VPN тоже не всегда идеален: нужно поднимать сервер, настраивать клиентов, разбираться с маршрутизацией, чинить доступ с мобильных сетей. И в какой-то момент ты понимаешь, что занимаешься не сервисами, а сетью. Вот здесь и выходит на сцену Netbird.\nЧто такое NetBird # NetBird - это система, которая создаёт приватную mesh-сеть между всеми твоими устройствами. Проще говоря:\nВсе твои серверы, ноутбуки, телефоны и контейнеры становятся частью одной виртуальной сети.\nИ всё это:\nбез проброса портов без ручной настройки WireGuard без сложной сетевой логики Чем он отличается от Pangolin # Если коротко:\nPangolin - публикует сервисы наружу (разной степени доступа конечно) NetBird - соединяет устройства между собой Но сейчас граница размылась. NetBird теперь умеет: делать приватную сеть (его основная функция); давать доступ к ресурсам; публиковать сервисы наружу через встроенный прокси. Последнее уже новая функция, которая полностью меняет восприятие этого приложения.\nТо есть он превращается в универсальный инструмент доступа.\nОсновная идея: mesh-сеть # Вместо классического VPN (клиент → сервер), NetBird использует mesh сеть:\nустройства соединяются напрямую если не получается - используется relay маршруты строятся автоматически Под капотом используется wireguard, но ты с ним почти не взаимодействуешь.\nПочему это удобно # 1. Никаких открытых портов # Твой сервер сам инициирует соединение наружу.\nЭто значит, что: не нужно трогать роутер; не нужно открывать порты; меньше рисков, связанных с возможной компрометацией сервисов.\n2. Всё шифруется # Трафик идёт через WireGuard. На практике - это значит современная криптография, высокая производительность, минимальные пинги\n3. Zero Trust подход # NetBird не доверяет сети - только пользователю и устройству. Ты контролируешь: кто именно подключается; к каким ресурсам подключается пользователь и по каким правилам (вернее ролям, так как там внедрен RBAC, хотя и на начальной стадии )\n4. Простота # Тебе не надо писать конфиги вручную, генерировать ключи и дебажишь iptables\nТы просто устанавливаешь агента, логинишься и получаешь сеть.\nБезусловно это не все возможности приложения, но я надеюсь, что читатели меня простят, если я не буду просто переводить сайт с документацией NetBird\nНовая фишка Netbird: публикация сервисов # Раньше NetBird был чисто про организацию приватной сети и получения к ней доступа. Теперь он умеет работать как обратный прокси. Это означает:\nты можешь публиковать сервисы наружу; без прямого открытия портов на домашнем сервере; с контролем доступа. Фактически, внутренний сервис → доступен по домену; трафик проходит через NetBird; доступ тонко регулируется политиками. Это делает его похожим на:\nPangolin Cloudflare Tunnel Но с важным отличием от Cloudflare Tunnel:\nвсё остаётся под твоим контролем\nКак это работает # Общая схема # У тебя есть management server (в нашем случае это self-hosted сервер на VPS) Устройства подключаются к нему Между ними строится mesh-сеть При необходимости поднимается relay или используется direct connection Компоненты # Management Server # Центральная точка управления:\nпользователи устройства политики доступа Agents # Клиенты, которые ставятся на:\nсерверы ПК ноутбуки контейнеры Relay (если нужен) # Используется, если прямое соединение невозможно (NAT, CGNAT и т.д.)\nВстроенный прокси # Отвечает за:\nпубликацию сервисов маршрутизацию трафика доступ извне Ключевые сценарии использования # 1. Доступ к homelab из любой точки # Ты просто подключаешься - и:\nоткрываешь Proxmox подключаешься к NAS подключаешься по SSH Как будто ты дома.\n2. Объединение нескольких организаций # Например дом, VPS, офис\nВсе они становятся одной сетью.\n3. Публикация сервисов # Теперь можно открыть доступ к веб-приложению по доменному имени, выдать доступ конкретным пользователям, не светить IP\n4. Безопасный доступ для команды # Можно дать доступ разработчикам, друзьям и коллегам. Но это если они у тебя конечно есть.\nМожно все сделать и в обратную сторону и ограничить все только нужными сервисами и только нужными портами\nТребования к развертыванию # Минимальный набор # Сервер (VPS или локальный) Домен Интернет-доступ у клиентов В этом требования у Pangolin и NetBird похожи\nВарианты развертывания # Облачный (самый простой) # Использовать hosted-версию NetBird.\nПлюсы:\nбыстро не нужна предварительная настройка. Минусы:\nменьше контроля доступ из России на дату публикации статьи затруднен Self-hosted (рекомендуется для homelab) в 2026 году # Ты поднимаешь:\nmanagement server с помощью установочного скрипта, который ты берешь на сайте разработчика, отвечаешь на пару вопросов, установка проходит в автоматическом режиме. И полностью контролируешь инфраструктуру.\nПодготовка сервера # Базовые шаги:\nсоздать пользователя (не root) настроить SSH включить firewall открыть нужные порты (всё как обычно для любого VPS)\nНиже примерный перечень действий, которые можно будет реализовать на VPS до развертывания NetBird\nПроцесс подготовки VPS # Базовая настройка безопасности VPS # После получения VPS первым шагом необходимо выполнить базовую настройку безопасности, чтобы минимизировать риски несанкционированного доступа. В первую очередь следует отказаться от работы под пользователем root и создать отдельного пользователя с правами sudo.\nРаботать под пользователем root небезопасно, поэтому сначала создадим нового пользователя и добавим его в группу sudo:\nadduser youruser usermod -aG sudo youruser Проверим, что всё работает:\nsu - youruser sudo whoami Настройка SSH (смена порта и отключение root) # Открываем конфигурационный файл SSH:\nsudo nano /etc/ssh/sshd_config Находим и изменяем следующие параметры:\nPort 2222 (ставить такой порт это большая ошибка) PermitRootLogin no Это:\nизменит стандартный порт SSH (22 → любой свободный нестандартный порт ) полностью запретит вход под root Отключение входа по паролю (крайне рекомендуется) # Для дополнительной защиты рекомендуется разрешить только вход по SSH-ключам:\nWarning Включайте этот параметр только если у вас уже настроены SSH-ключи, иначе можно потерять доступ к серверу.\nPasswordAuthentication no Настройка firewall (UFW) # Установим и включим UFW:\nsudo apt update sudo apt install -y ufw Разрешим только необходимые порты для работы Pangolin:\nsudo ufw allow номерпортадляssh,еслитыневключилдоступтолькопоключам/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 51820/udp Активируем firewall:\nsudo ufw enable sudo ufw status Применение изменений SSH # После внесения изменений перезапускаем SSH-сервис:\nsudo systemctl restart ssh Обязательная проверка подключения # Перед тем как завершить текущую SSH-сессию, откройте новое подключение и убедитесь, что всё работает:\nssh youruser@your_ip -p номерпортадляssh,еслитыневключилдоступтолькопоключам Только после успешного подключения можно закрывать старую сессию.\nНастройка DNS # Базовые DNS-записи\nВам потребуется создать записи типа A (или AAAA для IPv6), указывающие на IP-адрес вашего VPS.\n1. Создание wildcard-записи # 2. Ожидание распространения DNS # Изменения DNS могут распространяться от 5 минут до 48 часов по всему миру.\nReverse Proxy # Reverse Proxy в NetBird позволяет публиковать внутренние сервисы, запущенные на пирах (peers) или за сетевыми ресурсами, в публичный интернет. NetBird выполняет завершение TLS (TLS termination), при необходимости применяет аутентификацию и ограничения доступа, а также проксирует входящий трафик через mesh-сеть NetBird к целевому сервису - без необходимости открывать порты или настраивать firewall на внутренних машинах.\nДоступность: функция Reverse Proxy в настоящее время находится в стадии beta.\nТребование для self-hosted: в self-hosted развертываниях необходимо использовать Traefik в качестве внешнего reverse proxy. Это единственный поддерживаемый прокси, обеспечивающий TLS passthrough, необходимый для корректной работы функции Reverse Proxy.\nКак это работает # При создании сервиса reverse proxy NetBird автоматически выделяет публичный домен с TLS-сертификатом. Входящий трафик к этому домену поступает в кластер прокси NetBird, затем пересылается через зашифрованный туннель NetBird к целевому пиру или сетевому ресурсу, где запущено ваше приложение.\nЦелевой сервис должен быть доступен только внутри сети NetBird - ему не требуется публичный IP-адрес или открытые порты.\nNetBird поддерживает два типа сервисов:\nHTTP-сервисы (Layer 7)\nTLS завершается на прокси, далее HTTP-запросы проксируются на backend.\nПоддерживаются: маршрутизация по пути (path-based routing) проброс заголовка Host переписывание редиректов браузерная аутентификация (SSO, пароль, PIN) L4-сервисы (TCP, UDP, TLS)\nРаботают на уровне транспорта (Layer 4).\nПрокси пересылает соединения или датаграммы без анализа содержимого.\nВ режиме TLS используется SNI-маршрутизация без завершения TLS. Можно включить аутентификацию и ограничить доступ по IP или стране.\nКонцепция # Services (Сервисы) # Сервис - это основная единица конфигурации reverse proxy.\nСервис включает:\nРежим сервиса - HTTP (L7) или TCP/UDP/TLS (L4) Домен - публичный URL Targets - backend-цели Аутентификация - SSO / пароль / PIN / заголовки Ограничения доступа - IP, страна, CrowdSec Настройки Включение/выключение Service modes (Режимы) # Режим Уровень Описание HTTP L7 Завершение TLS + HTTP-прокси TCP L4 Прямой TCP relay UDP L4 UDP relay с отслеживанием сессий TLS L4 TLS passthrough с SNI Особенности L4:\nиспользуют отдельный порт нет HTTP-аутентификации можно использовать только ограничения доступа Targets (Цели) # Target определяет, куда отправляется трафик внутри сети NetBird.\nТипы:\nPeer - узел с агентом NetBird Host - IP-адрес Domain - доменное имя Subnet - подсеть (CIDR) Для HTTP: # Path (опционально) Protocol: HTTP / HTTPS Port (по умолчанию 80/443) Для L4: # только тип + порт Domains (Домены) # Cloud # Формат:\n{subdomain}.{nonce}.{cluster}.proxy.netbird.io\nПример:\nmyapp.abc123.eu.proxy.netbird.io\nSelf-hosted # {subdomain}.{proxy-domain}\nПример:\nmyapp.proxy.mycompany.com\nDNS (self-hosted) # Необходимо:\nA-запись → сервер NetBird CNAME: proxy *.proxy Custom domains # Можно использовать собственные домены через CNAME.\nВсе домены получают автоматические TLS-сертификаты.\nAuthentication (Аутентификация) # Метод HTTP L4 SSO Да Нет Password Да Нет PIN Да Нет Header Да Нет Access restrictions Да Да Если нет защиты - сервис публичный.\nService statuses # Статус Значение pending создаётся certificate_pending выпускается TLS active активен tunnel_not_created туннель не создан certificate_failed ошибка TLS error общая ошибка Prerequisites # Перед созданием:\nесть peer или network есть домен (self-hosted) есть proxy-инстанс есть права доступа Быстрый старт # Шаг 1 # Dashboard → Reverse Proxy → Services → Add Service\nШаг 2 # Настройки:\nрежим (HTTP / L4) subdomain base domain порт (для L4) target Шаг 3 (HTTP) # Аутентификация:\nSSO пароль PIN header Шаг 3b # Access control:\nIP страна CrowdSec Шаг 4 # Доп. настройки:\nHTTP: # Pass Host Header Rewrite Redirects L4: # PROXY Protocol Session timeout (UDP) ⚠️ Backend должен доверять proxy (trusted proxies)\nШаг 5 # Создание сервиса → ожидание active\nУправление сервисами # редактирование включение/выключение удаление управление targets Порты L4 # один сервис = один порт возможен auto или manual выбор нельзя пересекаться Особенности:\nHTTP и TLS могут делить порт через SNI TCP fallback при отсутствии SNI ⚠️ Нельзя использовать один hostname для HTTP и TLS\nPath-based routing # Пример:\nPath Target / app /api API /docs docs Более подробно как устанавливается это приложение у меня в видео ролике, и это тот случай, когда лучше один раз увидеть, чем сто раз прочитать.\n","date":"22 May 2026","externalUrl":null,"permalink":"/posts/netbird/","section":"Posts","summary":"Netbird позволяет публиковать локальные сервисы в интернет без открытия портов, используя безопасные туннели и удобный веб-интерфейс - идеальное решение для домашнего сервера и homelab.","title":"NetBird - публикация сервисов без белого IP и проброса портов","type":"posts"},{"content":"","date":"22 May 2026","externalUrl":null,"permalink":"/tags/security/","section":"Tags","summary":"","title":"Security","type":"tags"},{"content":"","date":"13 May 2026","externalUrl":null,"permalink":"/tags/pangolin/","section":"Tags","summary":"","title":"Pangolin","type":"tags"},{"content":"В случае если вам понравилась эта статья, то можете поддержать автора, став спонсором на Boosty.\nЕсли вы думали, что эта статья будет посвящена забавному млекопитающему панголину, то вы ошиблись.\nNote Но раз уж вы спросили, то скажу, что панголин - редкое млекопитающее, покрытое твёрдой чешуёй, напоминающей броню. Он питается муравьями и термитами, добывая их длинным липким языком. При опасности сворачивается в плотный шар, защищаясь от хищников.\nПредисловие # В homelabbing есть одна огромная болевая точка, с которой сталкивается почти каждый, кто поднимает себе домашний сервер. Сначала всё работает «локально»: сервисы крутятся, веб-интерфейсы открываются, всё красиво, ты всем доволен. Вроде бы. А потом хочется зайти к себе извне - и начинается цирк с конями в виде проброса портов, NAT, белых IP, динамического DNS, доменных имён и вечного ощущения, что ты где-то оставил дверь приоткрытой, куда вот-вот побежит весь интернет (кстати, если у тебя паранойя, это не значит что к весь интернет не побежит).\nВ этот момент на сцену выходит Pangolin.\nПо сути, это инструмент, который убирает из уравнения самую неприятную часть - открытые порты. Ты не лезешь в настройки роутера, не ковыряешь firewall и не думаешь: какой порт ты забыл закрыть; открыть; отключил ли ты доступ по SSH; что делать в случае компрометации твоих сервисов или «засвета» IP-адреса и так далее. Pangolin просто поднимает защищённый туннель наружу и даёт тебе доступ к сервисам так, будто они уже «снаружи», хотя физически всё остаётся у тебя дома.\nИ в этом его главный кайф - он снимает когнитивную нагрузку: не нужно держать в голове сетевую топологию; не нужно вспоминать, чем отличается DNAT от SNAT; не нужно переживать, что очередной сервис торчит в интернет без аутентификации или она слабая (а может не слабая, но ты не знаешь, а посоветоваться не с кем; а если есть с кем, то возможно он тебя интеллигентно послал, в смысле промолчал); что зря ты на роутере сэкономил или повелся на рекламу и так далее. С Pangolin ты описываешь, что именно хочешь открыть - вернее, какой сервис или сервер - и Pangolin делает это аккуратно и безопасно.\nОтдельно хочу отметить, что наконец-то всё это не выглядит как набор костылей, который постарались впихнуть во что-то бесформенное и потому отторгающее. Есть нормальный интерфейс, понятная логика и ощущение, что это не «ещё один GitHub-проект энтузиаста для энтузиастов», а цельный и, что самое главное, стабильный инструмент. Он не пытается быть всем сразу - просто решает конкретную задачу: дать доступ к твоим сервисам без лишнего геморроя (простите за мой французский).\nФактически, Pangolin - замена Cloudflare Tunnels, только без Cloudflare. Это твоё личное приложение. Ведь суть self-hosting именно в этом, правда?\nНо, конечно, за комфорт приходится платить. И тут каждый решает сам: либо ты тратишь время и нервы, вручную настраивая сеть и безопасность; тратишь время на изучение вопроса и набивание шишек (без этого никак); либо платишь за инструмент, который это уже сделал за тебя. Pangolin как раз про второй вариант.\nNote Отмечу, что платишь ты не за само приложение - оно для физических лиц бесплатное. Речь про инфраструктуру. Да, можно развернуть приложение у себя на домашнем сервере, но с учётом потенциальных расходов - белый айпи, требований к качеству сети, электропитанию и так далее, не исключено, что аренда VPS будет стоить в итоге столько же, как если бы ты всё разворачивал у себя. Зато злоумышленник в случае компрометации сервера дальше VPS не пройдёт. Так что тут решение исключительно за вами.\nВ итоге это история не столько про технологии, сколько про удобство. Про тот момент, когда ты хочешь, чтобы всё просто работало, без танцев с бубном и вечных проверок «а точно ли я всё закрыл», открыты ли у меня только порты 80 и 443 (а в зависимости от твоего софта может быть и больше, например если речь о SIP). И если ты уже устал от этой сопутствующей нервотрёпки - скорее всего, ты поймёшь, зачем вообще существует Pangolin.\nОсобенности приложения # Если копнуть еще глубже, Pangolin интересен не тем, что «работает из коробки», а тем, как именно он это делает. Под капотом - понятный стек современных сетевых подходов, аккуратно собранный в одно целое.\nВ основе лежит идея туннелирования. Вместо того чтобы принимать входящие соединения, твой сервер сам устанавливает исходящее соединение к внешней точке. Это важный момент: исходящие соединения почти всегда разрешены в обычных файрволлах, поэтому не нужно открывать порты на роутере. Дальше весь трафик к твоим сервисам просто прокидывается через этот туннель обратно внутрь.\nПоверх этого используется шифрование - как правило, на базе TLS. То есть трафик не просто «идёт через какой-то канал», а защищён от перехвата. По сути, это похоже на то, как работают VPN или решения вроде Cloudflare Tunnel: у тебя есть доверенный канал, внутри которого уже живут твои HTTP, SSH или любые другие сервисы.\nДальше включается проксирование. Pangolin выступает как обратный прокси: он принимает запросы снаружи и направляет их к нужному сервису внутри твоей сети. Это значит, что можно вешать несколько сервисов на один внешний вход, разруливать домены, пути и всё остальное, не трогая саму сеть.\nКонечно, есть нормальная система аутентификации. Вместо того чтобы надеяться, что «никто не найдёт мой порт» (когда он у тебя 2222 ), Pangolin делает ставку на контроль доступа: кто может подключаться, к чему именно и при каких условиях. Это популярный zero-trust подход.\nПлюс ко всему, такие решения обычно завязаны на агентную модель. У тебя есть клиент (агент), который крутится рядом с сервисами, и есть управляющая часть, которая знает, как эти сервисы опубликовать. Благодаря этому можно централизованно управлять доступом и не настраивать каждый контейнер или сервер отдельно.\nВ итоге Pangolin - приложение, которое одновременно интегрирует обратный прокси Traefik, протокол WireGuard, CrowdSec, а также возможность интеграции с любым известным IdP и IAM-провайдером. И как вишенка на торте - удобный Geo-Blocking, что позволяет нам заблокировать сразу входящие соединения оттуда, откуда мы их не ждем (а это практически ото всюду, кроме страны проживания, ну и еще одной, наверно, может быть, ну ты понял, да?).\nПо отдельности про все эти приложения я уже неоднократно рассказывал как в статьях, так и в видео на канале. Но ценность Pangolin в том, что тебе не нужно собирать этот конструктор самому из Traefik, WireGuard, Crowdsec, Authelia/Authentik и ещё пары компонентов. Всё уже собрано и работает как единая система.\nЦена развертывания сервиса # С Pangolin есть один нюанс, который многие пропускают на старте: он кажется «простым», пока не начинаешь разворачивать его правильно. Потому что сам по себе он работает из коробки, но чтобы он работал стабильно, безопасно и без сюрпризов - нужно соблюсти несколько базовых условий.\nВо-первых, тебе нужен сервер, который будет постоянно доступен из интернета. Это может быть VPS или любой внешний хост с белым IP. Именно туда Pangolin будет поднимать туннели, и именно эта точка станет «входом» в твой homelab. Без этого вся магия просто не сложится. В идеале - аренда VPS.\nДальше - домен. Можно, конечно, жить и без него, но нормальная работа с HTTPS, удобные адреса сервисов и в целом адекватный UX начинаются именно с домена. Плюс тебе придётся настроить DNS так, чтобы он указывал на внешний сервер.\nСледующий момент - сертификаты. Pangolin работает через защищённые соединения, поэтому TLS здесь не опция, а необходимый элемент. Хорошая новость в том, что чаще всего это автоматизируется через Let\u0026rsquo;s Encrypt, и руками почти ничего делать не нужно - главное, чтобы DNS был настроен правильно.\nНа стороне твоего домашнего сервера всё гораздо проще. Там достаточно запустить агент Pangolin, который установит исходящее соединение. И вот здесь ключевой плюс: никаких открытых портов, никаких изменений в роутере. Главное, чтобы сервер мог выходить в интернет.\nМенее очевидная часть - сеть и DNS внутри твоей инфраструктуры. Если ты хочешь, чтобы всё выглядело красиво и работало без костылей, стоит продумать, как сервисы будут резолвиться, как ты будешь разделять внутренний и внешний доступ и не возникнет ли конфликтов между ними.\nКонечно, базовая безопасность. Даже если Pangolin сам по себе закрывает много дыр, это не повод запускать всё с дефолтными настройками. Пароли, доступы, ограничения - всё это по-прежнему важно. Zero trust - это не только про инструмент, но и про то, как ты его используешь.\nВ итоге правильное развёртывание Pangolin - это не про «запустил контейнер, пользуйся и забыл про настройки». Это про связку из внешнего сервера, домена, нормального TLS и аккуратной, точечной настройки доступа. Если это всё есть, дальше он действительно начинает ощущаться как супер-приложение, которое снимает многие проблемы.\nКак работает Pangolin # Основные шаги # Объединяйте удалённые сети через коннекторы сайтов. Лёгкие коннекторы Pangolin используют умную маршрутизацию и обход NAT, чтобы любая сеть была доступна из любого места. Создавайте ресурсы, представляющие сервисы или целые диапазоны сети, доступные для удалённого подключения. Ресурсы могут быть публичными или полностью приватными. Авторизованные пользователи могут подключаться к ресурсам через веб-браузер или клиент Pangolin на своём устройстве. Ключевые концепции # Pangolin использует несколько компонентов, которые работают вместе для безопасного удалённого доступа. Каждый компонент выполняет свою роль, чтобы только авторизованные пользователи могли получать доступ к разрешённым ресурсам.\nСервер Pangolin # Сервер Pangolin - центральный компонент координации вашей сети. Он хранит конфигурацию, управляет политиками доступа и координирует соединения между клиентами и сайтами.\nСайты (Sites) # Сайты подключают удалённые сети к серверу Pangolin через защищённые туннели.\nРесурсы (Resources) # Ресурсы - это приложения, хосты или диапазоны сети, доступные пользователям.\nКлиенты (Clients) # Клиенты позволяют пользователям подключаться к ресурсам через защищённый туннель.\nУдалённые узлы (Remote Nodes) # Удалённые узлы - это ваши серверы Pangolin с полной управляемостью и контролем над данными.\nАрхитектура системы Pangolin # Pangolin состоит из нескольких ключевых компонентов, которые взаимодействуют друг с другом, обеспечивая безопасный удалённый доступ к сервисам без необходимости открывать порты.\nControl Plane # Control Plane - это мозг системы, управляющий всеми компонентами.\nGerbil # Gerbil отвечает за WireGuard-туннели.\nNewt # Newt - лёгкий клиент для подключения удалённых узлов.\nTraefik - обратный прокси # Маршрутизирует входящие запросы.\nBadger # Отвечает за аутентификацию и контроль доступа.\nТребования к установке и установка Pangolin # Необходимые условия # Linux-сервер с root-доступом и публичным IP Домен Email для SSL Открытые порты: 80, 443, 51820, 21820 Процесс подготовки VPS # Базовая настройка безопасности VPS # После получения VPS первым шагом необходимо выполнить базовую настройку безопасности, чтобы минимизировать риски несанкционированного доступа. В первую очередь следует отказаться от работы под пользователем root и создать отдельного пользователя с правами sudo.\nРаботать под пользователем root небезопасно, поэтому сначала создадим нового пользователя и добавим его в группу sudo:\nadduser youruser usermod -aG sudo youruser Проверим, что всё работает:\nsu - youruser sudo whoami Настройка SSH (смена порта и отключение root) # Открываем конфигурационный файл SSH:\nsudo nano /etc/ssh/sshd_config Находим и изменяем следующие параметры:\nPort 2222 (ставить такой порт это большая ошибка) PermitRootLogin no Это:\nизменит стандартный порт SSH (22 → любой свободный нестандартный порт ) полностью запретит вход под root Отключение входа по паролю (крайне рекомендуется) # Для дополнительной защиты рекомендуется разрешить только вход по SSH-ключам:\nWarning Включайте этот параметр только если у вас уже настроены SSH-ключи, иначе можно потерять доступ к серверу.\nPasswordAuthentication no Настройка firewall (UFW) # Установим и включим UFW:\nsudo apt update sudo apt install -y ufw Разрешим только необходимые порты для работы Pangolin:\nsudo ufw allow номерпортадляssh,еслитыневключилдоступтолькопоключам/tcp sudo ufw allow 80/tcp sudo ufw allow 443/tcp sudo ufw allow 51820/udp sudo ufw allow 21820/udp Активируем firewall:\nsudo ufw enable sudo ufw status Применение изменений SSH # После внесения изменений перезапускаем SSH-сервис:\nsudo systemctl restart ssh Обязательная проверка подключения # Перед тем как завершить текущую SSH-сессию, откройте новое подключение и убедитесь, что всё работает:\nssh youruser@your_ip -p номерпортадляssh,еслитыневключилдоступтолькопоключам Только после успешного подключения можно закрывать старую сессию.\nНастройка DNS # Базовые DNS-записи\nВам потребуется создать записи типа A (или AAAA для IPv6), указывающие на IP-адрес вашего VPS. # 1. Создание wildcard-записи # Создайте wildcard-запись поддомена для вашего домена:\nТип: A Имя: * Значение: айпи адрес твоего впс TTL: 300 (или по умолчанию) Это позволит любому поддомену (например, app.example.com, api.example.com) указывать на ваш VPS. # 2. Создание записи для корневого домена (необязательно) # Если вы планируете использовать корневой домен как ресурс:\nТип: A Имя: @ (или оставить пустым) Значение: айпи адрес твоего впс TTL: 300 (или по умолчанию) Эта запись нужна только в том случае, если вы хотите использовать example.com (а не только поддомены). # 3. Ожидание распространения DNS # Изменения DNS могут распространяться от 5 минут до 48 часов по всему миру.\nПроцесс установки # Установка Pangolin с помощью официального скрипта # Скачать установщик Это самая простая процедура. Да, можно все сделать самому, но в итоге это большой ручной труд с неясным результатом, и требующим большее погружение в проблему Подключитесь к серверу через SSH и выполните команду: curl -fsSL https://static.pangolin.net/get-installer.sh | bash Запустить установщик Выполните установку с root-привилегиями:\nsudo ./installer Установщик помещает все файлы в текущую директорию. Перед запуском можно переместить его в желаемую папку для установки.\nНастройка базовых параметров # Установщик запросит ключевые настройки: Edition: выберите Community Edition или Enterprise Edition Base Domain: укажите корневой домен без поддоменов (например, example.com) Dashboard Domain: нажмите Enter для значения по умолчанию pangolin.example.com или укажите свой домен Let’s Encrypt Email: адрес для SSL и входа администратора Tunneling: установка Gerbil для туннелей (по умолчанию: да). Можно работать без туннелей, как стандартный обратный прокси Настройка почты (опционально) Функционал электронной почты можно добавить позже. По умолчанию: Нет (рекомендуется при первичной установке) Если включено: укажите SMTP-сервер (host, port, username, password)\nЗапуск установки Подтвердите запуск установки:\nУстановщик скачает Docker-образы (pangolin, gerbil, traefik) Контейнеры будут запущены автоматически Процесс занимает 2–3 минуты в зависимости от скорости интернета Установка CrowdSec (опционально) Установщик предложит добавить CrowdSec для дополнительной защиты: По умолчанию: Нет (рекомендуется для начальной установки) При включении: нужно будет управлять конфигурацией CrowdSec вручную CrowdSec можно установить позже. Базовая установка уже обеспечивает достаточный уровень безопасности.\nНастройка после установки # После успешной установки вы увидите сообщение:\nInstallation complete!\nДля завершения первоначальной настройки перейдите по адресу: `https://pangolin.твойдомен.com/auth/initial-setup` Доступ к панели управления\nПерейдите по URL, указанному в выводе установщика: https://pangolin.твойдомен.com/auth/initial-setup\nSSL-сертификат будет настроен автоматически. Первичная валидация может занять несколько минут, поэтому возможны предупреждения о безопасности в браузере.\nСоздание учётной записи администратора\nВведите адрес электронной почты администратора Задайте надёжный пароль Подтвердите почту (если настроена)\nИспользуйте уникальный и сложный пароль - этот аккаунт имеет полный доступ к системе.\nСоздание первой организации\nПосле входа: Укажите название и описание организации Нажмите «Create Organization»\nТеперь вы готовы добавлять приложения и настраивать обратный прокси.\nБолее подробно как устанавливается это приложение у меня в видеоролике, и это тот случай, когда лучше один раз увидеть, чем сто раз прочитать.\n","date":"13 May 2026","externalUrl":null,"permalink":"/posts/pangolin/","section":"Posts","summary":"Pangolin позволяет публиковать локальные сервисы в интернет без открытия портов, используя безопасные туннели и удобный веб-интерфейс - идеальное решение для домашнего сервера и homelab.","title":"Pangolin — простой способ открыть доступ к homelab","type":"posts"},{"content":"","date":"24 April 2026","externalUrl":null,"permalink":"/categories/backup/","section":"Categories","summary":"","title":"Backup","type":"categories"},{"content":"","date":"24 April 2026","externalUrl":null,"permalink":"/series/backup/","section":"Series","summary":"","title":"Backup","type":"series"},{"content":"","date":"24 April 2026","externalUrl":null,"permalink":"/tags/zerobyte/","section":"Tags","summary":"","title":"Zerobyte","type":"tags"},{"content":" Note Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти.\nZerobyte: автоматизация резервного копирования для Homelab # Резервное копирование - одна из ключевых задач любой инфраструктуры.\nВ домашнем Homelab или self-hosted окружении важно иметь систему, которая:\nавтоматически выполняет бэкапы поддерживает шифрование умеет работать с облачными хранилищами имеет удобный интерфейс управления Именно такую задачу решает Zerobyte.\nВ этой статье разберём:\nчто такое Zerobyte как установить его через Docker как настроить первое резервное копирование как восстанавливать данные Что такое Zerobyte # Zerobyte - это инструмент для автоматизации резервного копирования, который помогает сохранять данные на различных хранилищах. Построенный на основе Restic, он предоставляет современный веб-интерфейс для планирования, управления и мониторинга зашифрованных резервных копий вашего удалённого хранилища.\nWarning Zerobyte всё ещё находится на версии 0.x.x и может существенно меняться от версии к версии. Проект в стадии активной разработки.\nПосле того, как я выпустил ролик про приложения-открытия 2025 года, в числе которых я рассказывал про Zerobyte, мне часто пишут с вопросом, почему я не рассказал о том или ином решении. По мнению задающего вопросы именно то приложение которым он пользуется самое лучшее:) Ниже я постарался свести в некую табличку особенности самых популярных решений.\nОсобенности Zerobyte:\nАвтоматическое резервное копирование с шифрованием, сжатием и политиками хранения, реализованное с помощью Restic Гибкое расписание для автоматических заданий резервного копирования с тонкой настройкой политики хранения Конечное шифрование (end-to-end), обеспечивающее защиту данных на всех этапах Поддержка нескольких протоколов: резервное копирование с NFS, SMB, WebDAV, SFTP или локальных директорий Это делает Zerobyte удобной альтернативой таким решениям как:\nDuplicati Kopia BorgBackup Сравнение популярных решений для резервного копирования # Backup tool Web UI Encryption Deduplication Docker Duplicati ✔ ✔ ✔ ✔ Kopia ✔ ✔ ✔ ✔ BorgBackup ✖ ✔ ✔ ✔ Zerobyte ✔ ✔ ✔ ✔ Сравнение Duplicati vs ZeroByte - сравнение систем резервного копирования # Так как в предыдущей статье я рассказывал про приложение Duplicati, то давайте сравним Duplicati и героя сегодняшней статьи более подробно.\nDuplicati и ZeroByte - это решения для резервного копирования данных, ориентированные на self-hosted инфраструктуру и домашние лаборатории. Оба инструмента предоставляют веб-интерфейс, автоматизацию и поддержку удалённых хранилищ, однако они используют разные архитектурные подходы.\nDuplicati - это самостоятельная система резервного копирования со своим движком.\nZeroByte - это веб-интерфейс и менеджер задач резервного копирования, построенный поверх backup-движка restic.\nКраткая таблица сравнения # Критерий Duplicati ZeroByte Тип решения Самостоятельная система резервного копирования Менеджер резервных копий Backup-движок Собственный Restic Архитектура Монолитное приложение Web UI + restic backend Интерфейс Web UI + CLI Web UI Шифрование AES-256 Встроенное шифрование restic Дедупликация Блочная дедупликация Дедупликация restic Инкрементальные бэкапы Да Да Сжатие Да Да Версионирование файлов Да Да Восстановление файлов Да Да Планировщик задач Да Да Поддержка облачных хранилищ Да Через restic или с помощью rclone Локальные хранилища Да Да Поддержка S3 Да Да Поддержка WebDAV Да Да Поддержка SFTP Да Да Поддержка rclone Нет Да Управление несколькими задачами Да Да Контроль snapshot-ов Да Да Логи и мониторинг Да Да Открытый исходный код Да Да Зрелость проекта Высокая Новый проект Простота установки Очень простая Простая Гибкость конфигурации Средняя Высокая Архитектура решений # Duplicati # Duplicati представляет собой полностью автономную систему резервного копирования.\nПриложение включает:\nbackup-движок веб-интерфейс систему планирования поддержку облачных хранилищ механизм дедупликации шифрование Благодаря этому Duplicati можно установить как единое приложение и сразу использовать для создания резервных копий.\nZeroByte # ZeroByte работает иначе. Это интерфейс управления для restic, популярного backup-движка.\nZeroByte добавляет:\nвеб-панель управления создание backup-задач управление расписанием просмотр snapshot-ов восстановление файлов централизованное управление несколькими репозиториями Фактически ZeroByte выполняет роль панели управления для restic-инфраструктуры.\nПоддерживаемые хранилища # Duplicati # Duplicati поддерживает большое количество облачных сервисов:\nAmazon S3 Backblaze B2 Google Drive OneDrive Dropbox WebDAV SFTP локальные диски NAS ZeroByte # ZeroByte использует возможности restic и может работать с:\nS3-совместимыми хранилищами локальными репозиториями SFTP WebDAV NAS rclone-backend Это делает ZeroByte удобным для более сложных инфраструктур. В принципе Zerobyte все, что поддерживает Duplicati, но за счет поддержки rclone имеет большую интеграцию с разнообразными облачными хранилищами.\nОсновные преимущества # Преимущества Duplicati # очень простая установка готовая система резервного копирования поддерживает самые распространненые облачные хранилища зрелый и хорошо известный проект удобный web-интерфейс Duplicati отлично подходит для:\nдомашних серверов NAS персональных бэкапов небольших homelab-инфраструктур Преимущества ZeroByte # современная архитектура использование надёжного backup-движка restic поддержка rclone-хранилищ гибкая работа с репозиториями удобное управление snapshot-ами ZeroByte лучше подходит для:\nпродвинутых homelab инфраструктур с несколькими backup-задачами пользователей restic Когда выбрать Duplicati # Duplicati стоит выбрать, если:\nнужна простая система резервного копирования важна быстрая установка требуется поддержка популярных облачных сервисов инфраструктура небольшая Duplicati - хороший выбор для большинства домашних серверов.\nКогда выбрать ZeroByte # ZeroByte лучше выбрать, если:\nвы уже используете restic нужна более гибкая архитектура backup-системы требуется поддержка rclone-backend есть несколько backup-репозиториев Итог сравнения Duplicati и ZeroByte # Инструмент Лучше всего подходит для Duplicati Простые и быстрые бэкапы для домашнего сервера ZeroByte Управление restic-бэкапами и более гибкие инфраструктуры Оба инструмента являются open-source и могут использоваться в self-hosted среде. Выбор зависит от того, нужен ли вам готовый backup-клиент (Duplicati) или менеджер инфраструктуры бэкапов на базе restic (ZeroByte).\nОсновные возможности Web интерфейса Zerobyte # Web-интерфейс # Zerobyte предоставляет современную web-панель управления, через которую можно:\nсоздавать backup-задачи запускать бэкапы вручную отслеживать статус восстанавливать файлы Использование Restic # В основе Zerobyte используется Restic, что даёт:\nдедупликацию шифрование инкрементальные бэкапы поддержку множества backend-хранилищ Поддерживаемые хранилища # Бэкапы можно хранить в:\nS3 Backblaze B2 SFTP локальном диске NAS WebDAV Docker Compose файл из видео # services: # Объявление всех сервисов (контейнеров), которыми управляет Docker Compose zerobyte: # Имя сервиса (логическое имя контейнера) image: ghcr.io/nicotsx/zerobyte:latest # Образ контейнера с фиксированной версией (лучше, чем latest) container_name: zerobyte # Явное имя контейнера для удобства управления (docker ps, логи и т.д.) restart: unless-stopped # Автоматический рестарт контейнера при падении (кроме ручной остановки) cap_add: - SYS_ADMIN # Добавляет расширенные привилегии (нужно для FUSE и работы с удалёнными шарами). Если бекапите локальные данные, закомментируйте строку - SYS_PTRACE # Позволяет отслеживать процессы (может использоваться для отладки или внутренней логики) Если бекапите локальные данные, закомментируйте строку #ports: # - \u0026#34;4096:4096\u0026#34; # Проброс порта наружу (не нужен, если используется Traefik) devices: - /dev/fuse:/dev/fuse # Проброс FUSE-устройства для работы с rclone/монтированием. Если бекапите локальные данные, закомментируйте строку environment: # Переменные окружения для настройки приложения - TZ=Europe/Moscow # Таймзона контейнера (важно для расписаний и логов) - BASE_URL=https://zerobyte.stilicho.ru # Публичный URL доступа к Zerobyte (используется в UI и OAuth) - APP_SECRET=240728b5d3d99fc4c233964e9836a2acf341fae4f72544d1a2051acc1339923d # Секрет приложения (обязательно уникальный, для безопасности) security_opt: # Ослабление механизмов безопасности контейнера - seccomp:unconfined # Отключает seccomp профиль (разрешает больше системных вызовов) Если бекапите локальные данные, закомментируйте строку - apparmor:unconfined # Отключает AppArmor профиль (снимает ограничения доступа) Если бекапите локальные данные, закомментируйте строку volumes: # Монтирование директорий (данные и доступ к файлам) - /etc/localtime:/etc/localtime:ro # Синхронизация времени с хостом (read-only) - /home/stilicho/docker/zerobyte:/var/lib/zerobyte # Данные Zerobyte (конфиги, база, состояние) - /home/stilicho/docker:/mydata # Директория с данными для бэкапа (источник volumes) networks: proxy: # Подключение к сети proxy (для работы с Traefik) labels: # Метки для автоматической конфигурации Traefik - \u0026#34;traefik.enable=true\u0026#34; # Включает обработку контейнера Traefik - \u0026#34;traefik.http.routers.zerobyte.entrypoints=web\u0026#34; # HTTP вход (порт 80) - \u0026#34;traefik.http.routers.zerobyte.rule=Host(`zerobyte.stilicho.ru`)\u0026#34; # Маршрутизация по домену - \u0026#34;traefik.http.middlewares.zerobyte-https-redirect.redirectscheme.scheme=https\u0026#34; # Редирект HTTP → HTTPS - \u0026#34;traefik.http.routers.zerobyte.middlewares=zerobyte-https-redirect\u0026#34; # Применение редиректа - \u0026#34;traefik.http.routers.zerobyte-secure.entrypoints=websecure\u0026#34; # HTTPS вход (порт 443) - \u0026#34;traefik.http.routers.zerobyte-secure.rule=Host(`zerobyte.stilicho.ru`)\u0026#34; # HTTPS правило маршрутизации - \u0026#34;traefik.http.routers.zerobyte-secure.tls=true\u0026#34; # Включение TLS (HTTPS) - \u0026#34;traefik.http.routers.zerobyte-secure.service=zerobyte\u0026#34; # Привязка к сервису - \u0026#34;traefik.http.services.zerobyte.loadbalancer.server.port=4096\u0026#34; # Внутренний порт приложения в контейнере - \u0026#34;traefik.docker.network=proxy\u0026#34; # Указание сети для Traefik networks: # Объявление сетей proxy: # Имя сети external: true # Сеть уже создана (Docker Compose не будет её создавать) Warning Раздел cap_add и devices дают излишние права. Используйте их только в случае если понимаете возможные последствия. Например в моем случае, без указанных параметров не было возможности подключиться к smb шаре на Truenas\nРабота с приложением # Приложение достаточно легковесное, образ быстро скачивается и также быстро разворачивается. После это переходим по поддоменному имени, которые мы присвоили нашему приложению, в моем случае - это `zerobyte.stilicho.ru\nНас приветствует окно первичной регистрации, где мы должны задать значения логина и пароля администратора, указать адрес электронной почты и скачать recovery key для восстановления из резервной копии (в случае если такое потребуется).\nОкно первоначальной регистрации\nОкно для введения данных регистрации и опции для скачивания ключа восстановления Нас приветствует приятный ретро интерфейс (угловатый как мой Мерседес W124) в красно-черных тонах. Если вы ситх, а в добавок еще и любитель ретро, то этот интерфейс вам очень понравиться\nТак как в начале статьи есть ссылка на мой видеообзор, то с вашего позволения ниже я ограничусь кратким описанием мею\nКак я рассказывал в видео, то пользователь должен настроить местоположение источника для бекапирования и целевой ресурс, куда будет осуществляться бекапирование.\nСоответственно раздел Volumes это \u0026ldquo;что мы будем бекапировать и местоположение файлов\u0026rdquo;\nРаздел Repositories отвечает за настройку целевого ресурса, куда мы все бекапируем\nРаздел Backups позволяет нам тонко настраивать работы по резервному бекапированию, в том числе, но не ограничиваясь: когда, во сколько начинать процедуру резервоного копирования, сколько копий хранить и т.д.\nВ разделе Notification мы с вам настраиваем каким образом и с помощью чего мы хотим получать уведомления\nНу и в самом низу настройки администрирования\n","date":"24 April 2026","externalUrl":null,"permalink":"/posts/zerobyte/","section":"Posts","summary":"Пошаговое руководство по установке и настройке Zerobyte для автоматизации резервного копирования в self-hosted инфраструктуре и homelab.","title":"Zerobyte - автоматизация резервного копирования для self-hosted инфраструктуры","type":"posts"},{"content":"","date":"17 April 2026","externalUrl":null,"permalink":"/tags/duplicati/","section":"Tags","summary":"","title":"Duplicati","type":"tags"},{"content":"Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти.\nDuplicati + Docker: автоматические бэкапы за 10 минут # Резервные копии - одна из самых важных частей любой инфраструктуры.\nДаже в домашнем Homelab, да и, собственно говоря, везде, потеря данных может стоить очень дорого. Причём речь идёт не только о самих данных, но и о времени, которое потребуется на их восстановление. Не исключено, что последнее окажется даже дороже.\nNote У меня на YouTube-канале есть ролик про установку и настройку Proxmox Backup Server. Но это решение специфическое, и не все используют Proxmox в Homelab.\nВ этой статье разберём:\nчто такое Duplicati как установить его на сервер как настроить автоматические бэкапы как хранить резервные копии локально и в облаке Что такое Duplicati # Duplicati - это open-source система резервного копирования, которая поддерживает:\nшифрование AES-256 дедупликацию инкрементальные бэкапы хранение в облаках web-интерфейс управления Поддерживаемые хранилища:\nS3 Backblaze B2 Google Drive WebDAV FTP / SFTP локальные диски NAS Это делает его отличным решением для Homelab и self-hosted инфраструктуры, так как поддерживает все что надо обычному хоумлабберу.\nОсновные возможности # Из основных возможностей, наверное, стоит обратить внимание на:\nШифрование # Все данные могут шифроваться на стороне клиента перед отправкой.\nПоддерживаются:\nAES-256 passphrase-защита Это означает, что даже облачный провайдер не сможет прочитать ваши данные. То есть можно быть относительно спокойным за бэкапы в облаке и за то, что никто не будет тренировать свои ИИ-модели на ваших данных.\nИнкрементальные бэкапы # Duplicati хранит данные блоками.\nЭто позволяет:\nсохранять только изменения уменьшать объём хранилища ускорять резервное копирование Так как система сохраняет только ту информацию, которая изменилась, то все происходит очень быстро, а нам проще планировать объем дискового пространства\nWeb-интерфейс # После установки вы получаете удобную web-панель.\nЧерез неё можно:\nсоздавать задания управлять расписанием восстанавливать файлы проверять состояние бэкапов Тут, в общем-то, всё понятно. Конечно, администраторы со стажем могут кривить рот - мол, графический интерфейс это «пошло». Но не поддавайтесь на провокации. Интерфейс - это нормально. Если, конечно, его не школьник рисовал.\nDocker compose файл из видео # За основу я взял образ (сборку) от linuxserver.io как наиболее user-friendly вариант для homelab\nservices: # Раздел для описания всех сервисов Docker duplicati: # Имя сервиса image: linuxserver/duplicati:latest # Образ Docker, последняя версия Duplicati от LinuxServer container_name: duplicati # Имя контейнера в Docker hostname: duplicati # Имя хоста внутри контейнера entrypoint: # Переопределение точки входа контейнера - /init # Используется скрипт /init, предоставляемый образом LinuxServer #ports: # Публикация портов контейнера на хосте # - 8200:8200 # MGMT UI - интерфейс управления Duplicati будет доступен на порту 8200 #expose: # Порт, который будет виден другим контейнерам в сети Docker # - 8200 environment: # Переменные окружения для контейнера - PUID=0 # UID пользователя внутри контейнера (0 = root, обычно для теста/администрирования) - PGID=1000 # GID группы внутри контейнера (должен соответствовать вашей группе на хосте) - TZ=Europe/Moscow # Часовой пояс для контейнера - SETTINGS_ENCRYPTION_KEY=B2NcaR2X6gwSGt # Ключ шифрования Duplicati (необходимо изменить!) - DUPLICATI__WEBSERVICE_PASSWORD=adminadminadmin # Пароль для веб-интерфейса (изменить обязательно!) restart: unless-stopped # Контейнер автоматически перезапустится, если он упадет, кроме явной остановки volumes: # Монтирование директорий хоста в контейнер - /home/stilicho/docker/duplicati/backups:/backups # Директория для хранения бэкапов - /home/stilicho/docker/duplicati/config:/config # Конфигурация и настройки Duplicati - /home/stilicho/docker:/source # Директория с исходными файлами для бэкапа (можно изменить) networks: # Сеть Docker, в которой будет работать контейнер - proxy labels: # Метки для Traefik (обратного прокси) - \u0026#34;traefik.enable=true\u0026#34; # Включить обработку Traefik для этого контейнера - \u0026#34;traefik.docker.network=proxy\u0026#34; # Использовать сеть proxy для Traefik - \u0026#34;traefik.http.routers.duplicati.entrypoints=web\u0026#34; # Входной пункт Traefik (порт 80) - \u0026#34;traefik.http.routers.duplicati.rule=Host(`duplicati.stilicho.ru`)\u0026#34; # Домен, по которому доступен сервис - \u0026#34;traefik.http.middlewares.duplicati-https-redirect.redirectscheme.scheme=https\u0026#34; # Перенаправление HTTP -\u0026gt; HTTPS - \u0026#34;traefik.http.routers.duplicati.middlewares=duplicati-https-redirect\u0026#34; # Подключаем middleware для редиректа - \u0026#34;traefik.http.routers.duplicati-secure.entrypoints=websecure\u0026#34; # HTTPS маршрут Traefik (порт 443) - \u0026#34;traefik.http.routers.duplicati-secure.rule=Host(`duplicati.stilicho.ru`)\u0026#34; # Домен HTTPS - \u0026#34;traefik.http.routers.duplicati-secure.tls=true\u0026#34; # Включаем TLS - \u0026#34;traefik.http.routers.duplicati-secure.tls.certresolver=cloudflare\u0026#34; # Используем Cloudflare для генерации сертификата - \u0026#34;traefik.http.routers.duplicati-secure.service=duplicati\u0026#34; # Назначаем сервис для маршрута - \u0026#34;traefik.http.services.duplicati.loadbalancer.server.port=8200\u0026#34; # Порт сервиса внутри контейнера для Traefik #- traefik.http.routers.duplicati.middlewares=ipwhitelist@file # (закомментировано) пример ограничения по IP networks: # Раздел для описания сетей proxy: # Сеть с именем proxy external: true # Используем внешнюю сеть Docker, созданную заранее (например для Traefik) Important PUID=0 означает root в контейнере. Для production лучше использовать непривилегированного пользователя. SETTINGS_ENCRYPTION_KEY и DUPLICATI__WEBSERVICE_PASSWORD обязательно нужно менять на свои, иначе данные и веб-интерфейс небезопасны. /source монтируется весь /home/stilicho/docker, если не нужно все бэкапить - лучше сузить путь до конкретных папок. Traefik labels управляют HTTPS и редиректами. Если Traefik ещё не настроен - их можно удалить до настройки прокси. пароли и другие чувствительные данные желательно указывать с помощью отдельного файла с окружением .env Работа с приложением # Так как у меня есть видеообзор, в этой статье я остановлюсь только на ключевых деталях.\nПосле установки приложения переходим по поддоменному имени. Откроется окно приветствия, где нужно ввести пароль администратора, указанный в docker-compose файле.\nНас встречает довольно минималистичное меню с «выжигающим роговицу» светлым режимом. Ночной режим можно включить в разделе Settings.\nВ разделе Add backup можно выбрать нужное действие: создать новый бэкап или восстановить его из конфигурационного файла (если он у вас есть).\nТак как нам нужно создать бэкап, выбираем опцию Add new backup.\nВ появившемся меню задаём необходимые параметры. При желании можно включить шифрование бэкапа.\nВ следующих двух окнах выбираем:\nместо хранения бэкапа используемый сервис В видео я выбрал File system, так как бэкапил демонстрационные файлы на примонтированное через fstab хранилище.\nПриложение предложит протестировать соединение.\nЕсли всё в порядке, в следующем окне нужно выбрать файлы для резервного копирования.\nВ нашем случае выбираем директорию source, так как она указана в docker-compose файле:\n/home/stilicho/docker:/source # Директория с исходными файлами для бэкапа (можно изменить) Далее задаём расписание бэкапов.\nВ следующем окне настраиваются дополнительные параметры: размер томов, количество хранимых копий и так далее.\nПосле завершения настройки в разделе Home появятся ваши задания для резервного копирования.\nКак я уже писал выше, чтобы не усложнять статью, я не буду подробно разбирать процесс восстановления. В видеообзоре он показан, и там всё достаточно логично и интуитивно понятно.\n","date":"17 April 2026","externalUrl":null,"permalink":"/posts/duplicati/","section":"Posts","summary":"Пошаговая инструкция по установке и настройке Duplicati для автоматических зашифрованных бэкапов на домашнем сервере или в облако","title":"Duplicati - резервное копирование с шифрованием для домашнего сервера","type":"posts"},{"content":"","date":"April 2, 2026","externalUrl":null,"permalink":"/en/tags/books/","section":"Tags","summary":"","title":"Books","type":"tags"},{"content":"","date":"April 2, 2026","externalUrl":null,"permalink":"/en/tags/grimmory/","section":"Tags","summary":"","title":"Grimmory","type":"tags"},{"content":"If you enjoyed this article, you can support the author by becoming a sponsor on Boosty.\nIn one of my recent articles I talked about Booklore - a platform for managing your own web library.\nIn another article, dedicated to the best open-source apps of 2025, I named this app one of the discoveries of the year.\nBy a strange coincidence, just a couple of days before publishing the video review of this app, the author deleted the project.\nWhat happened to Booklore: breaking down the situation # The removal of the Booklore project came as a surprise to users, but if you look through the developer\u0026rsquo;s statements and the discussions on Reddit/GitHub, the real picture becomes clear.\nThe developer\u0026rsquo;s position # The project\u0026rsquo;s author published a thread on Reddit titled:\n\u0026ldquo;My side of the story, from the developer of BookLore\u0026rdquo;\nIt was an attempt to explain what was going on, but the key factor was not just his stance, but rather the users\u0026rsquo; reaction.\nOne telling comment:\n\u0026ldquo;you removed the API docs without notice\u0026rdquo;\nWhat this actually meant: # changes were made without warning; backward compatibility was broken. As a result, both users and integration developers suffered.\nConflict with the community # Over time, systemic problems in the developer\u0026rsquo;s interaction with users accumulated.\nThe main grievances included: # significant changes, up to and including breaking changes, made without notice; functionality being removed or broken; feedback that was weak to the point of nonexistent; The result was a classic open-source conflict:\ndeveloper vs. community\nThe abrupt disappearance of the project # At the moment of removal, users noted:\nthe GitHub repository became inaccessible (404) the Discord server disappeared there was no official announcement This looked like a purely emotional decision - a kind of reaction to criticism that was at times more than fair - and it was ugly toward ordinary users who had no idea what was going on.\nFork and licensing issues # An additional factor was the disputes around the license (AGPL-3.0).\nWhat happened: # forks of the project appeared (for example, Grimmory, the hero of today\u0026rsquo;s article) possible license violations were discussed conflicts arose around the use of the code The latter is actually far from rare - just look at the situation around OnlyOffice and Nextcloud.\nGrowing negativity around the project # Even before the removal, there were warning signs:\nbugs discussions of \u0026ldquo;is it still worth using Booklore\u0026rdquo; criticism of architectural decisions questions about telemetry. Yes, there were questions about that too. In other words, the project was already under pressure from its users.\nBottom line: the project was removed # In fact, Booklore\u0026rsquo;s removal wasn\u0026rsquo;t caused by any single reason, but by a whole chain of events.\nThe main takeaway # This isn\u0026rsquo;t the usual \u0026ldquo;the developer got burned out\u0026rdquo; story, like what recently happened with the very good project Palmr.\nIt\u0026rsquo;s more a case of poor communication → conflict → toxic environment → abrupt project removal.\nYour humble narrator knew nothing about any of this and calmly published a video about this project on various video platforms. Naturally, people wrote in the comments telling me I was wrong, that the project was already dead, and that the video was outdated. Fine - I have no conflict with the community, so here\u0026rsquo;s a replacement for you. As I mentioned above, the original Booklore project was quickly forked by the community. Since the original Booklore was published under the AGPL license, the Grimmory project is essentially a one-to-one relicensed Booklore, just with a new name. If you look at the config files, the original docker-compose file still uses the variable name \u0026ldquo;booklore.\u0026rdquo; In any case, since I ended up in a situation where I published an article that was already outdated by the publication date, I\u0026rsquo;m fixing that now.\nBelow is a working version of the docker-compose file and the environment file.\nservices: # Секция описания сервисов (контейнеров) booklore: # Имя сервиса BookLore image: grimmory/grimmory:latest # Docker-образ BookLore из Docker Hub (тег latest) # image: ghcr.io/booklore-app/booklore:latest # Альтернативный образ из GitHub Container Registry (закомментирован) container_name: grimmory # Явное имя контейнера в Docker environment: # Переменные окружения контейнера - USER_ID=${APP_USER_ID} # UID пользователя для работы контейнера (права на файлы) - GROUP_ID=${APP_GROUP_ID} # GID группы для файлов и каталогов - TZ=${TZ} # Часовой пояс контейнера - DATABASE_URL=${DATABASE_URL} # URL подключения к базе данных MariaDB - DATABASE_USERNAME=${DB_USER} # Имя пользователя базы данных - DATABASE_PASSWORD=${DB_PASSWORD} # Пароль пользователя базы данных - BOOKLORE_PORT=${BOOKLORE_PORT} # Внутренний порт BookLore depends_on: # Зависимости сервиса mariadb: # Зависимость от сервиса mariadb condition: service_healthy # Запуск только после успешного healthcheck БД ports: - \u0026#34;${BOOKLORE_PORT}:${BOOKLORE_PORT}\u0026#34; # Проброс порта: host → container (обычно не нужен при использовании Traefik) volumes: - ./data:/app/data # Данные приложения BookLore - ./books:/books # Каталог с библиотекой книг - ./bookdrop:/bookdrop # Папка для автоматического импорта книг healthcheck: # Проверка работоспособности контейнера test: wget -q -O - http://localhost:${BOOKLORE_PORT}/api/v1/healthcheck # HTTP-запрос к встроенному healthcheck API BookLore interval: 60s # Интервал между проверками retries: 5 # Количество попыток до признания контейнера unhealthy start_period: 60s # Время ожидания перед началом проверок timeout: 10s # Таймаут одной проверки restart: unless-stopped # Автоперезапуск контейнера (кроме ручной остановки) networks: proxy: # Подключение к внешней сети proxy (Traefik) labels: # Метки Docker для интеграции с Traefik - \u0026#34;traefik.enable=true\u0026#34; # Включаем обработку контейнера Traefik - \u0026#34;traefik.http.routers.grimmory.entrypoints=web\u0026#34; # HTTP-вход (порт 80) - \u0026#34;traefik.http.routers.grimmory.rule=Host(`grimmory.stilicho.ru`)\u0026#34; # Направляем трафик с домена grimmory.stilicho.ru в этот контейнер - \u0026#34;traefik.http.middlewares.grimmory-https-redirect.redirectscheme.scheme=https\u0026#34; # Middleware для редиректа HTTP → HTTPS - \u0026#34;traefik.http.routers.grimmory.middlewares=grimmory-https-redirect\u0026#34; # Применяем middleware редиректа к HTTP-маршруту - \u0026#34;traefik.http.routers.grimmory-secure.entrypoints=websecure\u0026#34; # HTTPS-вход (порт 443) - \u0026#34;traefik.http.routers.grimmory-secure.rule=Host(`grimmory.stilicho.ru`)\u0026#34; # HTTPS-маршрут для того же домена - \u0026#34;traefik.http.routers.grimmory-secure.tls=true\u0026#34; # Включаем TLS (HTTPS) - \u0026#34;traefik.http.routers.grimmory-secure.service=grimmory\u0026#34; # Привязываем HTTPS-роутер к сервису booklore - \u0026#34;traefik.http.services.grimmory.loadbalancer.server.port=6060\u0026#34; # Внутренний порт BookLore внутри контейнера - \u0026#34;traefik.docker.network=proxy\u0026#34; # Указываем Traefik, в какой Docker-сети искать контейнер # mariadb: # Сервис базы данных MariaDB image: lscr.io/linuxserver/mariadb:11.4.5 # Образ MariaDB от LinuxServer.io (стабильный и удобный) container_name: mariadb # Явное имя контейнера environment: # Переменные окружения MariaDB - PUID=${DB_USER_ID} # UID владельца файлов БД - PGID=${DB_GROUP_ID} # GID владельца файлов БД - TZ=${TZ} # Часовой пояс - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} # Пароль root-пользователя БД - MYSQL_DATABASE=${MYSQL_DATABASE} # Имя базы данных, создаваемой при первом запуске - MYSQL_USER=${DB_USER} # Пользователь БД - MYSQL_PASSWORD=${DB_PASSWORD} # Пароль пользователя БД volumes: - ./mariadb/config:/config # Каталог с данными и конфигурацией MariaDB restart: unless-stopped # Автоперезапуск контейнера healthcheck: # Проверка доступности БД test: [ \u0026#34;CMD\u0026#34;, \u0026#34;mariadb-admin\u0026#34;, \u0026#34;ping\u0026#34;, \u0026#34;-h\u0026#34;, \u0026#34;localhost\u0026#34; ] interval: 5s # Интервал проверки timeout: 5s # Таймаут проверки retries: 10 # Количество попыток networks: proxy: # Подключение к сети proxy (Traefik) networks: proxy: # Определение сети proxy external: true # Сеть уже существует и не создаётся Docker самостоятельно Environment file\n# ========================================================= # 🎯 BookLore - основные настройки приложения # ========================================================= APP_USER_ID=1000 # UID пользователя на хосте, от имени которого # BookLore будет работать внутри контейнера. # Нужен для корректных прав доступа к volume. APP_GROUP_ID=1000 # GID группы на хосте. # Должен совпадать с владельцем каталогов data / books / bookdrop. TZ=Europe/Moscow # Часовой пояс контейнеров. # Используется для логов, планировщиков и временных меток. BOOKLORE_PORT=6060 # Порт, на котором BookLore слушает внутри контейнера. # Также используется Traefik как внутренний порт сервиса. # ========================================================= # 🗄️ Подключение BookLore к базе данных MariaDB # ========================================================= DATABASE_URL=jdbc:mariadb://mariadb:3306/grimmory # JDBC-строка подключения к MariaDB: # - mariadb → имя сервиса в docker-compose # - 3306 → стандартный порт MariaDB # - grimmory → имя базы данных DB_USER=grimmory # Пользователь базы данных, # под которым BookLore подключается к MariaDB. DB_PASSWORD=ChangeMe_BookLoreApp_2025! # Пароль пользователя базы данных. # ⚠️ ОБЯЗАТЕЛЬНО сменить в продакшене. # ========================================================= # 🔧 Настройки контейнера MariaDB (инициализация) # ========================================================= DB_USER_ID=1000 # UID пользователя, от имени которого # MariaDB пишет данные в volume. DB_GROUP_ID=1000 # GID группы для файлов базы данных. MYSQL_ROOT_PASSWORD=ChangeMe_MariaDBRoot_2025! # Пароль root-пользователя MariaDB. # Используется только для администрирования БД. MYSQL_DATABASE=grimmory # Имя базы данных, которая будет автоматически # создана при первом запуске контейнера MariaDB. ","date":"April 2, 2026","externalUrl":null,"permalink":"/en/posts/grimmory/","section":"Posts","summary":"A detailed walkthrough for installing and configuring Grimmory: deploying it in Docker, adding books, organizing your library, and using the built-in web reader.","title":"Grimmory - a self-hosted library and reader for your book collection","type":"posts"},{"content":"","date":"16 March 2026","externalUrl":null,"permalink":"/tags/booklore/","section":"Tags","summary":"","title":"BookLore","type":"tags"},{"content":"Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти.\nWarning К сожалению статья уже неактуальна, так как разработчик не выдержал критиканства и удалил репозиторий.\nBookLore - self-hosted библиотека и веб-читалка для вашей коллекции книг # Если у вас есть большая коллекция электронных книг, рано или поздно появляется проблема - как удобно хранить, сортировать и читать эти книги. Простое хранение файлов в папках быстро превращается в хаос: сложно искать нужную книгу, отсутствуют обложки, нет описаний и невозможно отслеживать прогресс чтения.\nИменно для решения этой задачи существуют специальные приложения для управления библиотекой. Одним из таких решений является BookLore - современное веб-приложение с открытым исходным кодом, которое позволяет создать собственный сервер для хранения и чтения электронных книг.\nBookLore отлично подходит для:\nдомашнего сервера NAS homelab инфраструктуры личной или семейной библиотеки Приложение работает через браузер, поэтому получить доступ к библиотеке можно с компьютера, планшета или смартфона.\nЧто такое BookLore # BookLore - это система управления электронной библиотекой (Digital Library Server), которая позволяет:\nхранить книги в одном месте автоматически получать метаданные организовывать библиотеку по авторам и жанрам читать книги прямо в браузере отслеживать прогресс чтения создавать коллекции книг использовать несколько пользователей По сути, BookLore превращает ваш сервер в персональный сервис для чтения книг, похожий на Kindle Library или Google Books, но полностью находящийся под вашим контролем.\nЧем BookLore отличается от других решений # Существует несколько популярных приложений для управления библиотекой:\nCalibre-Web Kavita Audiobookshelf Однако BookLore имеет ряд особенностей, которые делают его интересным вариантом для домашнего сервера.\nСовременный интерфейс # BookLore предлагает современный и минималистичный веб-интерфейс.\nПреимущества интерфейса:\nудобная навигация карточки книг с обложками быстрый поиск по библиотеке адаптивный дизайн поддержка тёмной темы Интерфейс отлично работает как на компьютере, так и на мобильных устройствах.\nЯ прекрасно понимаю, что интерфейс - это субъективный вопрос, но дизайн все равно приятный.\nАвтоматическое получение метаданных # После добавления книг BookLore может автоматически загрузить:\nназвание книги автора описание обложку жанры Это позволяет быстро привести библиотеку в порядок даже если у вас сотни или тысячи книг, хотя с российскими изданиями, безусловно, могут быть проблемы.\nВстроенный ридер электронных книг # Одно из главных преимуществ BookLore - встроенный веб-ридер.\nПоддерживаются популярные форматы:\nEPUB PDF CBZ (комиксы) Это означает, что книги можно читать прямо в браузере, без скачивания на устройство.\nПоддержка нескольких пользователей # BookLore поддерживает многопользовательскую работу.\nКаждый пользователь может:\nиметь собственный прогресс чтения добавлять книги в избранное создавать коллекции делать закладки Это делает приложение удобным для семейной библиотеки или небольшого сообщества.\nПростая установка через Docker # BookLore легко устанавливается с помощью Docker, что делает его идеальным решением для:\nProxmox Docker-серверов NAS домашнего homelab Установка занимает всего несколько минут.\nУстановка BookLore с помощью Docker Compose # Самый простой способ развернуть BookLore - использовать Docker Compose.\nШаг 1. Создание рабочей директории # Создадим папку для приложения:\nmkdir booklore cd booklore Нам понадобятся два файла: docker-compose.yml и файл с переменными окружения.\nШаг 2. Docker Compose и переменные окружения # docker-compose.yml\nservices: # Секция описания сервисов (контейнеров) booklore: # Имя сервиса BookLore image: booklore/booklore:latest # Docker-образ BookLore из Docker Hub (тег latest) # image: ghcr.io/booklore-app/booklore:latest # Альтернативный образ из GitHub Container Registry (закомментирован) container_name: booklore # Явное имя контейнера в Docker environment: # Переменные окружения контейнера - USER_ID=${APP_USER_ID} # UID пользователя для работы контейнера (права на файлы) - GROUP_ID=${APP_GROUP_ID} # GID группы для файлов и каталогов - TZ=${TZ} # Часовой пояс контейнера - DATABASE_URL=${DATABASE_URL} # URL подключения к базе данных MariaDB - DATABASE_USERNAME=${DB_USER} # Имя пользователя базы данных - DATABASE_PASSWORD=${DB_PASSWORD} # Пароль пользователя базы данных - BOOKLORE_PORT=${BOOKLORE_PORT} # Внутренний порт BookLore depends_on: # Зависимости сервиса mariadb: # Зависимость от сервиса mariadb condition: service_healthy # Запуск только после успешного healthcheck БД ports: - \u0026#34;${BOOKLORE_PORT}:${BOOKLORE_PORT}\u0026#34; # Проброс порта: host → container (обычно не нужен при использовании Traefik) volumes: - ./data:/app/data # Данные приложения BookLore - ./books:/books # Каталог с библиотекой книг - ./bookdrop:/bookdrop # Папка для автоматического импорта книг healthcheck: # Проверка работоспособности контейнера test: wget -q -O - http://localhost:${BOOKLORE_PORT}/api/v1/healthcheck # HTTP-запрос к встроенному healthcheck API BookLore interval: 60s # Интервал между проверками retries: 5 # Количество попыток до признания контейнера unhealthy start_period: 60s # Время ожидания перед началом проверок timeout: 10s # Таймаут одной проверки restart: unless-stopped # Автоперезапуск контейнера (кроме ручной остановки) networks: proxy: # Подключение к внешней сети proxy (Traefik) labels: # Метки Docker для интеграции с Traefik - \u0026#34;traefik.enable=true\u0026#34; # Включаем обработку контейнера Traefik - \u0026#34;traefik.http.routers.booklore.entrypoints=web\u0026#34; # HTTP-вход (порт 80) - \u0026#34;traefik.http.routers.booklore.rule=Host(`booklore.domain.ru`)\u0026#34; # Направляем трафик с домена booklore.domain.ru в этот контейнер - \u0026#34;traefik.http.middlewares.booklore-https-redirect.redirectscheme.scheme=https\u0026#34; # Middleware для редиректа HTTP → HTTPS - \u0026#34;traefik.http.routers.booklore.middlewares=booklore-https-redirect\u0026#34; # Применяем middleware редиректа к HTTP-маршруту - \u0026#34;traefik.http.routers.booklore-secure.entrypoints=websecure\u0026#34; # HTTPS-вход (порт 443) - \u0026#34;traefik.http.routers.booklore-secure.rule=Host(`booklore.domain.ru`)\u0026#34; # HTTPS-маршрут для того же домена - \u0026#34;traefik.http.routers.booklore-secure.tls=true\u0026#34; # Включаем TLS (HTTPS) - \u0026#34;traefik.http.routers.booklore-secure.service=booklore\u0026#34; # Привязываем HTTPS-роутер к сервису booklore - \u0026#34;traefik.http.services.booklore.loadbalancer.server.port=6060\u0026#34; # Внутренний порт BookLore внутри контейнера - \u0026#34;traefik.docker.network=proxy\u0026#34; # Указываем Traefik, в какой Docker-сети искать контейнер mariadb: # Сервис базы данных MariaDB image: lscr.io/linuxserver/mariadb:11.4.5 # Образ MariaDB от LinuxServer.io (стабильный и удобный) container_name: mariadb # Явное имя контейнера environment: # Переменные окружения MariaDB - PUID=${DB_USER_ID} # UID владельца файлов БД - PGID=${DB_GROUP_ID} # GID владельца файлов БД - TZ=${TZ} # Часовой пояс - MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} # Пароль root-пользователя БД - MYSQL_DATABASE=${MYSQL_DATABASE} # Имя базы данных, создаваемой при первом запуске - MYSQL_USER=${DB_USER} # Пользователь БД - MYSQL_PASSWORD=${DB_PASSWORD} # Пароль пользователя БД volumes: - ./mariadb/config:/config # Каталог с данными и конфигурацией MariaDB restart: unless-stopped # Автоперезапуск контейнера healthcheck: # Проверка доступности БД test: [ \u0026#34;CMD\u0026#34;, \u0026#34;mariadb-admin\u0026#34;, \u0026#34;ping\u0026#34;, \u0026#34;-h\u0026#34;, \u0026#34;localhost\u0026#34; ] interval: 5s # Интервал проверки timeout: 5s # Таймаут проверки retries: 10 # Количество попыток networks: proxy: # Подключение к сети proxy (Traefik) networks: proxy: # Определение сети proxy external: true # Сеть уже существует и не создаётся Compose и файл с переменными .env\n# ========================================================= # 🎯 BookLore - основные настройки приложения # ========================================================= APP_USER_ID=0 # UID пользователя на хосте, от имени которого # BookLore будет работать внутри контейнера. # Нужен для корректных прав доступа к volume. APP_GROUP_ID=0 # GID группы на хосте. # Должен совпадать с владельцем каталогов data / books / bookdrop. TZ=Europe/Moscow # Часовой пояс контейнеров. # Используется для логов, планировщиков и временных меток. BOOKLORE_PORT=6060 # Порт, на котором BookLore слушает внутри контейнера. # Также используется Traefik как внутренний порт сервиса. # ========================================================= # 🗄️ Подключение BookLore к базе данных MariaDB # ========================================================= DATABASE_URL=jdbc:mariadb://mariadb:3306/booklore # JDBC-строка подключения к MariaDB: # - mariadb → имя сервиса в docker-compose # - 3306 → стандартный порт MariaDB # - booklore → имя базы данных DB_USER=booklore # Пользователь базы данных, # под которым BookLore подключается к MariaDB. DB_PASSWORD=ChangeMe_BookLoreApp_2025! # Пароль пользователя базы данных. # ⚠️ ОБЯЗАТЕЛЬНО сменить в продакшене. # ========================================================= # 🔧 Настройки контейнера MariaDB (инициализация) # ========================================================= DB_USER_ID=1000 # UID пользователя, от имени которого # MariaDB пишет данные в volume. DB_GROUP_ID=1000 # GID группы для файлов базы данных. MYSQL_ROOT_PASSWORD=ChangeMe_MariaDBRoot_2025! # Пароль root-пользователя MariaDB. # Используется только для администрирования БД. MYSQL_DATABASE=booklore # Имя базы данных, которая будет автоматически # создана при первом запуске контейнера MariaDB. Первичная настройка BookLore # После первого запуска необходимо выполнить начальную настройку системы.\nСоздание администратора # При первом открытии интерфейса BookLore предложит создать учётную запись администратора.\nНеобходимо указать:\nимя пользователя; пароль; адрес электронной почты (опционально). Этот пользователь получит полный доступ к настройкам системы.\nДобавление библиотеки книг # Следующий шаг - подключение папки с книгами.\nЕсли используется docker compose из примера выше, путь будет: /books.\nПосле добавления директории BookLore начнёт сканирование библиотеки.\nСканирование и импорт книг # Во время сканирования приложение автоматически:\nобнаруживает книги; извлекает метаданные; загружает обложки; формирует каталог библиотеки. Если библиотека большая, сканирование может занять некоторое время.\nНастройка источников метаданных # В настройках можно выбрать источники метаданных, которые используются для поиска информации о книгах.\nЭто позволяет автоматически получать:\nописания; обложки; жанры; дополнительные сведения о книге. Организация коллекций # Для удобной навигации можно создавать коллекции книг.\nНапример:\nфантастика; научная литература; классика; комиксы; технические книги. Книги можно добавлять в коллекции вручную или с помощью тегов.\nДобавление пользователей # Если библиотекой пользуются несколько человек, можно создать дополнительные учётные записи.\nКаждый пользователь сможет:\nчитать книги; сохранять прогресс; создавать закладки; формировать собственные списки книг. Итог # BookLore - это удобный и современный сервер для управления электронной библиотекой, который отлично подходит для домашнего сервера или homelab инфраструктуры.\nОсновные преимущества BookLore:\nсовременный веб-интерфейс; встроенный ридер электронных книг; автоматическое получение метаданных; поддержка нескольких пользователей; простая установка через Docker. Если у вас есть большая коллекция электронных книг и вы хотите получить удобный доступ к ней с любого устройства, BookLore станет отличным решением для организации собственной цифровой библиотеки.\nТакой сервер легко развернуть на домашнем оборудовании и получить полноценную альтернативу облачным сервисам для чтения книг.\n","date":"16 March 2026","externalUrl":null,"permalink":"/posts/booklore/","section":"Posts","summary":"Подробная инструкция по установке и настройке BookLore: развёртывание в Docker, добавление книг, организация библиотеки и использование встроенной веб-читалки.","title":"BookLore - self-hosted библиотека и читалка для вашей коллекции книг","type":"posts"},{"content":"","date":"5 March 2026","externalUrl":null,"permalink":"/categories/hardware/","section":"Categories","summary":"","title":"Hardware","type":"categories"},{"content":"","date":"5 March 2026","externalUrl":null,"permalink":"/tags/hardware/","section":"Tags","summary":"","title":"Hardware","type":"tags"},{"content":"","date":"5 March 2026","externalUrl":null,"permalink":"/tags/mini-server/","section":"Tags","summary":"","title":"Mini Server","type":"tags"},{"content":" ZimaBoard 2 - компактный x86-сервер для домашнего хомлаба # Note Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти.\nВведение # В мире homelab-энтузиастов постоянно идёт поиск баланса между компактностью, энергоэффективностью и реальной серверной функциональностью. Одноплатники вроде Raspberry Pi хороши для экспериментов, но быстро упираются в ARM-архитектуру, I/O и производительность. Мини-ПК мощные, но часто избыточны, дороже и не всегда дружелюбны к серверным сценариям.\nZimaBoard 2 - это попытка занять нишу между этими двумя мирами: компактный, холодный и экономичный x86-сервер, созданный специально для self-hosted задач и домашней хомлабы.\nЧто такое ZimaBoard 2 # ZimaBoard 2 - это одноплатный компьютер (SBC) на архитектуре x86-64, разработанный компанией IceWhale как развитие оригинального ZimaBoard. В отличие от классических SBC, он изначально ориентирован не на «подключить клавиатуру и монитор», а на серверное использование:\nработа 24/7 установка Linux, BSD, Proxmox, TrueNAS, ESXi запуск Docker, Podman, Kubernetes сетевые и “хранилищные” сервисы Формально это не NAS и не мини-ПК - это микросервер, в котором акцент сделан на сетевые возможности, стабильность и совместимость с серверным софтом с предустанновленной операционной системой ZimaOS.\nЗачем вообще нужен ZimaBoard 2 # Главная идея ZimaBoard 2 - дать полноценный x86-сервер в максимально компактном и энергоэффективном форм-факторе.\nОн нужен, если вам:\nнадоело ограничение ARM-плат хочется нативный Docker без костылей нужны SATA-диски без USB-адаптеров важна совместимость с Proxmox / ESXi хочется «включил и забыл» сервер для дома При этом ZimaBoard 2 не пытается конкурировать с полноценными серверами или мощными NUC - его задача закрывать базовые и средние homelab-сценарии с минимальными затратами.\nЦелевая аудитория # ZimaBoard 2 в первую очередь ориентирован на:\nHomelab-энтузиастов # Тех, кто:\nподнимает свои сервисы экспериментирует с сетями, прокси, SSO хочет отдельный сервер под тесты и прод Любителей self-hosted и Docker # Если у вас:\nTraefik / Nginx Authentik / Authelia / Keycloak Vaultwarden, Nextcloud, Jellyfin CrowdSec, Prometheus, Grafana ZimaBoard 2 отлично подходит как хост под контейнеры.\nDevOps / администраторов # Как:\nтестовый стенд edge-сервер VPN-шлюз reverse-proxy-узел CI/CD-раннер Роутер на базе OPNsense/pfSense Домашних пользователей, уставших от «облаков» # Для тех, кто хочет:\nхранить данные у себя иметь собственный NAS не зависеть от подписок и SaaS Почему ZimaBoard 2 - это про homelab # В homelab важны не «бенчмарки ради бенчмарков». К сожалению многие обзоры сводятся просто к замерам \u0026ldquo;безликих попугаев\u0026rdquo;, что просто неприменимо в реальной жизни. В homelab важна, ну или должны быть важна, если желаете, - практичность. И тут ZimaBoard 2 попадает точно в цель:\nx86-архитектура - ставится почти любой серверный дистрибутив SATA-порты - нормальные диски без USB Ethernet - стабильная сеть для сервисов Низкое энергопотребление - можно держать включённым постоянно Компактность и пассивное охлаждение - тихо и без обслуживания Это отличный кандидат на роль:\nпервого homelab-сервера отдельного узла под прокси / SSO мини-NAS edge-ноды в Proxmox-кластере сервера мониторинга или безопасности Почему ZimaBoard 2 во многих сценариях может быть лучше стандартного NAS типа Synology # Synology давно стала синонимом «домашнего NAS». Это удобные, \u0026ldquo;отполированные\u0026rdquo; устройства с хорошей экосистемой и простым интерфейсом. Но именно эта «коробочность» со временем начинает мешать - особенно если речь идёт не просто о хранении файлов, а о полноценном homelab.\nZimaBoard 2 предлагает принципиально другой подход.\n1. Полный контроль вместо закрытой экосистемы # Synology - это:\nпроприетарная DSM ограничения на версии пакетов зависимость от политики производителя невозможность нормально обновлять ядро или систему ZimaBoard 2 - это:\nчистый Linux / BSD / гипервизор полная свобода выбора ОС никаких искусственных ограничений стандартные репозитории и обновления В homelab это критично: сервер - ваш, а не «арендованный» у вендора.\n2. Нормальный Docker и контейнеризация # На Synology:\nDocker урезан часто старые версии проблемы с сетями, IPv6, macvlan ограничения по привилегиям контейнеров На ZimaBoard 2:\nнативный Docker полноценный iptables / nftables нормальная работа Traefik, Authentik, CrowdSec Если вы запускаете больше, чем пару контейнеров - ZimaBoard выигрывает сразу.\n3. Гипервизоры и виртуализация # Synology:\nвиртуализация доступна только на старших моделях жёсткие аппаратные ограничения привязка к DSM ZimaBoard 2:\nProxmox ESXi KVM / libvirt LXC-контейнеры Note устанавливать гипервизор на emmc нерекомендуется\n4. Железо без маркетинговых ограничений # Synology известна:\n«несовместимыми» дисками whitelist’ами иными странными ограничениями ZimaBoard 2:\nлюбые SATA-диски любые сетевые и программные конфигурации 5. Цена и ценность # За цену среднего Synology вы получаете:\nограниченное железо закрытую систему зависимость от DSM За сопоставимые деньги ZimaBoard 2 даёт:\nx86-платформу полноценный сервер гибкость и масштабируемость идеальную основу для homelab Когда Synology всё же лучше # Честности ради:\nSynology выигрывает, если вам нужно:\n«включил, работает, забыл» минимальная настройка пользователи без Linux-опыта простой файловый сервер для семьи Но как только появляются:\nreverse proxy SSO VPN self-hosted сервисы инфраструктурные эксперименты Synology быстро становится узким местом.\nВывод # ZimaBoard 2 - это не убийца Synology, или замена минипк, а шаг дальше.\nЕсли Synology - это бытовая техника, то ZimaBoard 2 - настоящий сервер в миниатюре.\nДля homelab, self-hosted и обучения инфраструктуре он:\nгибче честнее перспективнее И именно поэтому в среде homelab ZimaBoard 2 - может быть более правильным выбором, чем классический NAS, так как ZimaBoard 2 - это не «очередной одноплатник» и не «ещё один мини-ПК». Это осознанно спроектированный x86-микросервер, который закрывает реальные потребности homelab-сообщества.\n","date":"5 March 2026","externalUrl":null,"permalink":"/posts/zimaboard-2-overview/","section":"Posts","summary":"Разбираем ZimaBoard 2: характеристики, сценарии использования, производительность и применение в homelab - от Docker до виртуализации.","title":"ZimaBoard 2 — обзор мини-сервера для homelab","type":"posts"},{"content":"","date":"February 17, 2026","externalUrl":null,"permalink":"/en/tags/memos/","section":"Tags","summary":"","title":"Memos","type":"tags"},{"content":" Memos - a lightweight self-hosted note-taking app. Feature overview and homelab use cases # If you\u0026rsquo;re looking for a minimalist self-hosted note-taking app that can be deployed in Docker or an LXC container in Proxmox, Memos deserves your attention. It\u0026rsquo;s an open-source solution for keeping personal notes, a technical journal, and a knowledge base, without a bloated interface or unnecessary features.\nWhat Memos is and how it differs from other note-taking systems # Memos is a lightweight open-source note-taking app built around a timeline format. Unlike bloated services such as Notion or Obsidian, there\u0026rsquo;s no complex page hierarchy, databases, or block structures here.\nThe main idea is quickly capturing thoughts:\nshort text entries\nMarkdown support\nautomatic timestamping\ntags right in the text\nfast search\nPhilosophically, it\u0026rsquo;s closer to a \u0026ldquo;technical microblog\u0026rdquo; than a classic wiki.\nWhy Memos is a good fit for self-hosting and homelabs # Three things matter for a homelab:\nControl over your data\nEase of deployment\nMinimal resource requirements\nMemos checks all three boxes.\nKey features of Memos # 1. Timeline format # All notes are shown as a chronological feed. This is convenient for jotting down ideas for projects.\n2. Tags and filtering # Hashtags are supported:\n#docker #proxmox #traefik #auth You can filter by tags and quickly find entries. This is handy when maintaining notes.\n3. Multi-user support # Memos lets you:\ncreate users; isolate data; use roles. You can run a single instance for a family or a team.\n4. Minimal system requirements # Memos does not require:\na separate PostgreSQL instance; complex configuration; an external cache; heavy dependencies. This makes it an ideal candidate for:\nmini PCs; single-board computers; VPS. 5. A lightweight knowledge base # If you don\u0026rsquo;t need the complex hierarchy of Trilium Notes or a heavy PKM approach, Memos is a great fit for atomic notes.\nAdvantages of Memos: # Open-source\nSelf-hosted\nMinimalism\nFast deployment\nLow resource consumption\nDocker support\nPossible limitations # Memos won\u0026rsquo;t be a good fit if you need:\ncomplex nested structures\ndatabases inside notes\nkanban boards\nan advanced wiki system\nIt\u0026rsquo;s deliberately a minimalist tool.\nConclusion # Memos is an ideal self-hosted digital notebook for a homelab infrastructure.\nIf you need to:\nquickly jot down thoughts; store your data locally, it\u0026rsquo;s one of the simplest and most convenient solutions.\nSample docker compose file from the video # services: memos: image: neosmemo/memos:stable container_name: memos #ports: # - \u0026#34;5230:5230\u0026#34; volumes: - /home/user/docker/memos:/var/opt/memos environment: - MEMOS_MODE=prod - MEMOS_PORT=5230 restart: unless-stopped networks: proxy: # Подключаем контейнер к внешней сети \u0026#34;proxy\u0026#34; (используется Traefik) labels: # Метки для интеграции с Traefik (обратный прокси) - \u0026#34;traefik.enable=true\u0026#34; # Включаем обработку контейнера Traefik - \u0026#34;traefik.http.routers.memos.entrypoints=web\u0026#34; # Определяем HTTP-вход (порт 80) - \u0026#34;traefik.http.routers.memos.rule=Host(`memos.domain.ru`)\u0026#34; # Трафик на этот домен будет направляться в данный контейнер - \u0026#34;traefik.http.middlewares.memos-https-redirect.redirectscheme.scheme=https\u0026#34; # Middleware для редиректа с HTTP на HTTPS - \u0026#34;traefik.http.routers.memos.middlewares=memos-https-redirect\u0026#34; # Применяем middleware редиректа к HTTP-маршруту - \u0026#34;traefik.http.routers.memos-secure.entrypoints=websecure\u0026#34; # Определяем HTTPS-вход (порт 443) - \u0026#34;traefik.http.routers.memos-secure.rule=Host(`memos.domain.ru`)\u0026#34; # HTTPS-маршрут для того же домена - \u0026#34;traefik.http.routers.memos-secure.tls=true\u0026#34; # Включаем TLS (HTTPS) - \u0026#34;traefik.http.routers.memos-secure.service=memos\u0026#34; # Привязываем HTTPS-маршрут к сервису memos - \u0026#34;traefik.http.services.memos.loadbalancer.server.port=5230\u0026#34; # Указываем внутренний порт, на котором memos слушает в контейнере - \u0026#34;traefik.docker.network=proxy\u0026#34; # Указываем, что Traefik должен искать контейнер в сети \u0026#34;proxy\u0026#34; networks: proxy: # Определение внешней сети для взаимодействия с Traefik external: true # Сеть уже создана ранее (не создавать заново) ","date":"February 17, 2026","externalUrl":null,"permalink":"/en/posts/memos/","section":"Posts","summary":"We go through installing and configuring Memos - a minimalist self-hosted app for quick notes and a personal journal. I’ll show how to run it in Docker, its core features, how to organize notes, and homelab use cases.","title":"Memos — setting up self-hosted notes for quick thoughts","type":"posts"},{"content":"","date":"February 17, 2026","externalUrl":null,"permalink":"/en/categories/personal-knowledge-base/","section":"Categories","summary":"","title":"Personal Knowledge Base","type":"categories"},{"content":"","date":"February 17, 2026","externalUrl":null,"permalink":"/en/tags/pkm/","section":"Tags","summary":"","title":"PKM","type":"tags"},{"content":"A series of articles on configuring and using Authentik — a modern IdP and IAM provider.\nWe cover installing it in Docker and setting up secure access to our system and services. Hello world\n","date":"February 6, 2026","externalUrl":null,"permalink":"/en/posts/authentik/","section":"Posts","summary":"A series of articles on configuring and using Authentik — a modern IdP and IAM provider. We cover installing it in Docker and setting up secure access to our system and services.","title":"Authentik","type":"posts"},{"content":"","date":"February 6, 2026","externalUrl":null,"permalink":"/en/series/authentik/","section":"Series","summary":"","title":"Authentik","type":"series"},{"content":"","date":"February 6, 2026","externalUrl":null,"permalink":"/en/tags/authentik/","section":"Tags","summary":"","title":"Authentik","type":"tags"},{"content":"Policies provide configuration and flexibility when defining the user login and authentication process.\nEssentially, policies decide whether a given stage will be applied within a flow, as well as whether specific users can access that flow at all.\nFor example, you can create a policy that skips the MFA prompt stage for certain users. Or you could define a policy that only allows access to the login flow if certain conditions are met. In this article, I\u0026rsquo;ll look at the reputation policy.\nReputation Policy # Authentik tracks recent login attempts for each identifier (username, email address, etc.) and client IP address. These values are stored as scores. Failed login attempts decrease the score by 1, and successful ones increase it by 1.\nThis policy can be used, for example, to make users with a low score go through a CAPTCHA check before continuing to log in.\nUnder the administrator account, go to the Flows and Stages \u0026gt; Flows menu\nSelect your main identification flow, in my case default-authentication-flow, then go to the Policy/Groups/User Bindings section\nNext, go to Create and Bind Policy, and select Reputation Policy from the menu.\nIn the next section, give the policy a name that makes sense to you.\nNext comes a very important point to keep in mind. If you select both check ip and check username, then if, say, user Vanya fails a login attempt from a specific IP address, that access will be denied. But if, say, Galya successfully logs in from that same IP address, she will be granted access.\nIf you select only check ip, then failed login attempts from a specific IP address, regardless of username, will result in that IP being denied.\nConversely, if you select only check username, then failed login attempts under a specific username will result in that specific user being denied, regardless of the IP address they\u0026rsquo;re trying to authenticate from.\nChoose whichever option best fits your needs.\nThreshold is the value at which the policy kicks in. The default is -5.\nIn the next section, enable the Negate the result option.\nNote In short: Negate the result is a flag that inverts the policy\u0026rsquo;s outcome.\nPut simply:\ndisabled → the policy works \u0026ldquo;as is\u0026rdquo; enabled → the policy\u0026rsquo;s result gets flipped For example, suppose the policy returns:\ntrue - conditions are met false - conditions are not met If you enable Negate the result:\ntrue → becomes false false → becomes true Why is this needed in Authentik: this is handy when a policy defines a \u0026ldquo;bad\u0026rdquo; condition, but you need to react to the \u0026ldquo;good\u0026rdquo; one, or vice versa - applying a stage only when the conditions are NOT met.\nExample with the Reputation Policy: the policy checks score ≥ 0. Without negation, the stage is applied when the reputation is normal. With Negate the result, the stage is instead applied when the reputation is bad (for example, to show a CAPTCHA or block the login).\nAlso specify the policy\u0026rsquo;s order number.\nIn the Flow overview section, you can see how the flow now works.\nIf your reputation is good, you\u0026rsquo;ll be able to go through all authentication stages. If your reputation is below the configured threshold (in my case, three failed login attempts from the same IP address), Authentik simply won\u0026rsquo;t let you proceed further.\nYou can view reputation values in the Customisation → Reputation Scores menu.\nIn the next article, we\u0026rsquo;ll talk about setting up a policy based on the geographic location of the user\u0026rsquo;s IP address.\n","date":"February 6, 2026","externalUrl":null,"permalink":"/en/posts/authentik-reputaion-policy/","section":"Posts","summary":"A step-by-step setup of the Reputation Policy and GeoIP in Authentik for restricting access by IP reputation and country, with a breakdown of typical protection scenarios.","title":"Authentik: setting up a Reputation Policy","type":"posts"},{"content":"","date":"February 6, 2026","externalUrl":null,"permalink":"/en/categories/sso/","section":"Categories","summary":"","title":"SSO","type":"categories"},{"content":"","date":"February 6, 2026","externalUrl":null,"permalink":"/en/tags/sso/","section":"Tags","summary":"","title":"SSO","type":"tags"},{"content":" Note If you found this article useful and would like to thank the author, you can do so via the corresponding link on boosty\nIn this article I\u0026rsquo;ll talk about setting up email notifications in Authentik. They let you receive notifications about important events in the system - such as user logins, logouts, and authentication errors. This is useful for security monitoring and responding promptly to suspicious activity.\nTip For this setup, and for Authentik to work correctly in general, you need to have already configured your mail server settings in the .env environment variables file.\nYou can verify that SMTP is configured correctly with the following command:\ndocker exec authentik_worker ak test_email your_email@domain.com The authentik_worker container must be running, and the AUTHENTIK_EMAIL_* variables must be set correctly.\nNote The application settings described in this article are accurate as of the time of writing.\nLog in to Authentik as an administrator and go to:\nEvents → Notification Rules\nIn this article I\u0026rsquo;ll show notification setup for only three basic events, which I consider the most important from a security standpoint. If needed, you can configure any other events you like.\nClick Create. In the window that appears, give the rule a name that makes sense to you. In my case, this is a rule for monitoring logins to Authentik.\nIn the Groups section, specify which group\u0026rsquo;s users will receive the notifications. In my case, this is authentik Admins.\nIn the Transport section, choose the notification delivery mechanism. In this case, email is used.\nIn the Severity section, choose the importance level of the event. I use the Alert value, then click Create.\nGo to the rule we just created and click Create and Bind Policy.\nIn the window that appears, select Event Matcher Policy.\nGive the policy a name (for example, login). In the Action section, choose the event that will trigger the notification. In my case, this is Login.\nThe remaining parameters depend on your requirements - they\u0026rsquo;re described in more detail in the official documentation. If your goal is simply to get notified about the event without additional filtering, you can leave them unchanged, as shown in my screenshot.\nIn the next window, set the processing order for the policy. I start with a value of 10 and click Finish.\nTo keep track of key user actions (or potential attackers), I create two more similar policies. The only difference is the event type:\nLogout Failed Login As a result, the list of bound policies looks roughly like this:\nOnce configured, it\u0026rsquo;s recommended to run a test. To do this, you can log out and log back into Authentik, and also try logging in with incorrect credentials. If everything is set up correctly, an email notification will arrive for each corresponding event.\n","date":"February 5, 2026","externalUrl":null,"permalink":"/en/posts/authentik-email-notifications/","section":"Posts","summary":"A step-by-step guide to setting up email notifications in Authentik: connecting SMTP, enabling event notifications, configuring email templates, and verifying delivery.","title":"Setting up email notifications in Authentik","type":"posts"},{"content":" Disabling passwords and two-factor authentication for local users in Authentik # In some scenarios, using local passwords and two-factor authentication (2FA / MFA) in Authentik is redundant or even undesirable. This can apply to various scenarios, but for home use, constant authentication is clearly excessive.\nIn this article I\u0026rsquo;ll describe the process of properly disabling password authentication and MFA for local users in Authentik, while everything stays the same for external IPs.\nHow Authentik handles authentication # Authentication in Authentik is built on Flows and Stages:\nA Flow is a login scenario; A Stage is a single step within that scenario; Stages run strictly in the order specified; If a stage isn\u0026rsquo;t present in the flow, it doesn\u0026rsquo;t run at all. It\u0026rsquo;s important to understand: Authentik has no global \u0026ldquo;enable/disable password\u0026rdquo; switch. Everything is controlled through flows.\nThe role of the Password Stage and MFA Stage # The Password Stage is responsible for checking the local password; The MFA Stage handles TOTP, WebAuthn, and other factors. If:\nthe Password Stage is absent → the password is not requested or checked; the MFA Stage is absent → the second factor is not used. Disabling two-factor authentication in Authentik for local users who access Authentik via its IP address # Go to Customisation - Policies Create - Expression Policy Give the policy a name. In the Expression Policy section, write return ak_client_ip.is_private. Create Note You can read more in the official documentation\nGo to Flows and Stages - Flows Select our default-authentication-flow \u0026gt; Stage Bindings Click on default-authentication-mfa-validation Click Bind existing Policy In the window that appears, select the policy created in step 4 Make sure to enable both enable and negate result Create Now, if you access your Authentik instance not via its subdomain, but via its IP address:port, you won\u0026rsquo;t need to enter a username and password.\nDisabling the password requirement when local users authenticate from local IPs on the local network # The general approach is the same as in the previous section.\nGo to Flows and Stages - Flows Select default-authentication-flow \u0026gt; default-authentication-flow \u0026gt; Stage Bindings. Click Edit Stage next to default-authentication-identification. In the Password Stage section, make sure it\u0026rsquo;s set to a dash. This is needed in case you had username and password entered on the same page. If so, deactivate that feature and restore the corresponding stage (default-authentication-password). Select Bind existing Stage For the Stage, select our default-authentication-password Now click the arrow next to default-authentication-password \u0026gt; Bind existing Policy Do as shown in the screenshot above - bind the same Expression Policy with enable and negate result ","date":"January 16, 2026","externalUrl":null,"permalink":"/en/posts/authentik-disable-passwords-2fa/","section":"Posts","summary":"A step-by-step guide to disabling passwords and two-factor authentication for local Authentik users: setting up the authentication flow, stages, policies, and recommendations for safe use","title":"Disabling passwords and two-factor authentication for local users in Authentik","type":"posts"},{"content":" Setting up Cloudflare Turnstile in Authentik # Cloudflare Turnstile is a modern alternative to CAPTCHA that lets you protect authentication forms from bots and brute-force attacks without forcing users to decipher images or type in characters.\nNote If you found this article useful and would like to thank the author, you can do so via the corresponding link on boosty\nNote Cloudflare Turnstile is an analog of Captcha technology, but for Cloudflare users. If you specifically need to set up Captcha, you can read more in the official documentation\nNote As of July 1, 2025, changes to Russian personal data legislation (Federal Law No. 152) came into effect, under which using Google reCAPTCHA or its analogs on sites that transfer data abroad becomes a violation. Keep this restriction in mind if you plan to use this service for commercial activity.\nWhy use Cloudflare Turnstile in Authentik # By default, Authentik already has decent protection against:\nbrute-force attacks; username enumeration; automated login attempts. However, when exposing your IdP to the internet, this is often not enough.\nCloudflare Turnstile lets you:\nfilter out bots before the flow even runs; reduce the load on Authentik; improve the user experience compared to classic CAPTCHAs; raise the overall security level without complicating your flow logic. In other words, in addition to the authentication and authorization methods we already set up in previous articles, we\u0026rsquo;re adding one more verification method.\nVisually, it looks something like this\nRequirements # Before you start, make sure that:\nyou have a Cloudflare account; the domain where Authentik is hosted has been added to Cloudflare. Unfortunately, these are mandatory requirements for using this technology.\nCreating a Turnstile widget in Cloudflare # Go to the Cloudflare dashboard. Open the Security \u0026gt; Turnstile section (Cloudflare periodically moves menu items between sections — at the time of writing this was under \u0026ldquo;Protect \u0026amp; Connect\u0026rdquo;, now it\u0026rsquo;s moved to \u0026ldquo;Security\u0026rdquo;. If you still can\u0026rsquo;t find it, just search for \u0026ldquo;Turnstile\u0026rdquo; in the dashboard search). Click Add Widget (in some UI versions the button is already called Add site). Specify: Widget name - any name you like (e.g. authentik-login); Add Hostname \u0026gt; Domains - the domain where Authentik runs; Widget mode - Managed (recommended for home use). Pre-Clearance Mode - Yes Level of pre-clearance - interactive Note Change the last two settings however you see fit, depending on your needs and level of paranoia.\nOnce created, you\u0026rsquo;ll receive:\nSite Key Secret Key You can copy them, but Cloudflare kindly notes that you\u0026rsquo;ll always be able to access them again later.\nCreating a Captcha Stage in Authentik # Configuring the stage in Authentik # Now let\u0026rsquo;s move on to the configuration in Authentik.\nOpen the Authentik admin panel. Go to Flows and Stages → Stages. Click Create. Select Captcha Stage. Give the stage a name. For the verification type, select Cloudflare Turnstile. In the Public key and Private Key fields, enter the values we got from Cloudflare. You can leave the Interactive toggle enabled if your Turnstile is configured as Invisible or Managed. Don\u0026rsquo;t touch anything in the Advanced Settings section. In the version of Authentik current as of writing, the correct values are already filled in automatically. Previously you had to enter them manually. You can read more in the official documentation\nFinish Integrating the Turnstile stage into the main authentication and authorization flow # Open the Authentik admin panel. Go to Flows and Stages → Flows → default-authentication-flow. Select Stage Bindings → Bind Existing Stage Select the stage we just created. Choose the processing order for the Turnstile stage - after the authentication stage, but before the password entry stage. Select evaluate when flow is planned. Create We\u0026rsquo;ve now integrated the \u0026ldquo;captcha\u0026rdquo; stage into Authentik\u0026rsquo;s authentication process.\nTip In the Turnstile panel on the Cloudflare site, you can view analytics for this widget\n","date":"January 15, 2026","externalUrl":null,"permalink":"/en/posts/authentik-cloudflare-turnstile/","section":"Posts","summary":"A detailed guide to setting up Cloudflare Turnstile - a modern alternative to CAPTCHA for protecting login, registration, and password recovery forms without degrading the user experience.","title":"Cloudflare Turnstile in Authentik - setting up login form protection","type":"posts"},{"content":" Note If you found this article useful and would like to thank the author, you can do so via the corresponding link on boosty\nIn previous articles, we talked about how to create and recover passwords according to a policy we defined, and how to set up automated user registration. In this article, we\u0026rsquo;ll talk about setting up two-factor authentication, and we\u0026rsquo;ll configure it so that all users are required to set up two-factor authentication. I\u0026rsquo;ll show you how to set up authentication with TOTP codes and WebAuthn devices, and we\u0026rsquo;ll also set up passwordless login.\nTip The most secure authentication is using Yubikey solutions, but that\u0026rsquo;s an expensive option, you always need a spare key in case you lose the first one, and unfortunately I don\u0026rsquo;t have that hardware for a demo. And the Cisco Duo service is temporarily unavailable in Russia as of the time of writing.\nNote There\u0026rsquo;s already an article published on the site about the differences between TOTP, WebAuthn, and Passwordless Login. You can check it out here. So I\u0026rsquo;ll assume you already know what TOTP, WebAuthn, and Passwordless Login are.\nFirst of all, I should note that in this article I describe automating the process, which in my view is the most optimal approach. But everything can also be done manually. To do that, each user goes to their personal settings by clicking the gear icon in the top-right corner, and selects MFA Devices \u0026gt; Enroll\nIn the dropdown menu, select a TOTP or WebAuthn device and follow the instructions.\nWe\u0026rsquo;ll do the same thing, but at the global level, so that every Authentik user is required to set up two-factor authentication. For TOTP codes to work properly, you need to have any authenticator app you like installed: Google Authenticator, Vaultwarden, Bitwarden, Yandex.Key, or even Kaspersky Password Manager. Choose whichever solution is most convenient and comfortable for you. For WebAuthn and Passwordless Login, any device with fingerprint login or Windows Hello will work (I\u0026rsquo;m sure the Mac equivalent works too). I personally use a combination of Vaultwarden + Google Authenticator + Windows Hello. I\u0026rsquo;m performing all these actions from an administrator account.\nSetting up TOTP codes # In principle, as in previous articles, we could create all the necessary flows from scratch. But to keep things simple, let\u0026rsquo;s use the default flow. Go to Flow and Stages \u0026gt; Flows \u0026gt; default-authentication-flow. Within default-authentication-flow, go to Stage Bindings.\nRight now our stages look like this\nNow we need to make changes to the default default-authentication-mfa-validation stage. The thing is, it\u0026rsquo;s present in the list of stages for the default-authentication-flow, but it\u0026rsquo;s not configured and doesn\u0026rsquo;t do anything. Don\u0026rsquo;t worry, my young viewers, we\u0026rsquo;re about to fix that.\nIn the list that appears, under not configured action, select force the user to configure an authenticator. This forces the user to use two-factor authentication. In the configure stages menu that appears, select TOTP Authenticator Setup Stage and click Update.\nTip My personal opinion is that an admin should have several two-factor authentication options in case one of them fails.\nNow let\u0026rsquo;s log out of our account (it\u0026rsquo;s highly advisable to do everything in an incognito browser window to avoid later confusion about why nothing works). Log back in with our account, and after entering our login and password, we\u0026rsquo;ll be greeted by a TOTP device registration window. Scan the code with your smartphone using your TOTP app, enter the resulting six-digit code. That\u0026rsquo;s it, the device is registered. Now, on every login, after entering our username and password, we\u0026rsquo;ll need to enter a 6-digit code from our authenticator app.\nWarning The 6-digit code generated by the smartphone app is normally valid for 30 seconds. So it\u0026rsquo;s extremely important that the time zone is set correctly everywhere, especially in Authentik. Otherwise, if devices become desynchronized, your code may expire before you manage to enter it into Authentik.\nSetting up WebAuthn # WebAuthn (Web Authentication API) is a W3C and FIDO Alliance standard that lets you log in using cryptographic keys built into your device. This includes fingerprints, Windows Hello, Face ID, etc.\nActually, the whole procedure is virtually identical to what we did with TOTP, except for one detail. Go to Flow and Stages \u0026gt; Flows \u0026gt; default-authentication-flow. Within default-authentication-flow, go to Stage Bindings, and make changes to the default default-authentication-mfa-validation stage. In addition to the existing TOTP, add WebAuthn Authenticator Setup Stage.\nIn not configured action, leave force the user to configure an authenticator.\nLog out of the account, and now when we try to log in from our mobile device or computer using a fingerprint or face scan, we\u0026rsquo;ll have a choice: TOTP or WebAuthn. Note that if some form of two-factor auth is already registered on your account, you won\u0026rsquo;t get a list to choose an authentication method from, since you\u0026rsquo;ve already committed to one method earlier. So if you want to add another option alongside an existing one, you\u0026rsquo;ll have to add it manually in the user settings. From then on, you\u0026rsquo;ll have two-factor options to choose from.\nPasswordless Login # As I mentioned above, there\u0026rsquo;s an article on the site describing the specifics of passwordless login and why webauthn and passwordless login shouldn\u0026rsquo;t be seen as opposites. Specifically in our case, Passwordless login will let us skip entering a username and password and then scanning a fingerprint or face, and instead scan immediately. The scan serves as confirmation of both the login and the password.\nNote To set up passwordless login, you must first configure the WebAuthn login method.\nGo to Flow and Stages \u0026gt; Flows \u0026gt; Create.\nCreate a new flow. Give the flow whatever name you find suitable. For Designation, select Authentication and click Create\nIn the Flows section, click on our new flow \u0026gt; Stage Bindings \u0026gt; Create and bind stage \u0026gt; Authenticator Validation Stage\nNext. Again, give the stage a name. In the Device Classes section, select WebAuthn. This is needed because currently only security keys, like a Yubikey, or biometrics are supported.\nIn not configured action, leave force the user to configure an authenticator.\nScroll down a bit, and in the WebAuthn User verification field, choose whichever option suits your needs. I choose User verification must occur. In the Configuration Stages section, select WebAuthn Authenticator Setup Stage.\nClick Next and in the next menu choose the stage\u0026rsquo;s execution order and evaluate when stage is run.\nThat\u0026rsquo;s still not all. Now we need to bind the existing login stage.\nBind existing stage, select default-authentication-login and the order in which this stage should run, which must come after the new stage created in this section. Be sure to select evaluate when stage is run, then Create\nGo to Flows \u0026gt; default-authentication-flow \u0026gt; Stage Bindings \u0026gt; default-authentication-identification \u0026gt; Edit Stage. Scroll all the way down, and for Passwordless flow, select the flow we created, in my case passwordless-web-authn \u0026gt; Update.\nLog out of the application - now it depends on which device you\u0026rsquo;re using. If you\u0026rsquo;re on a laptop, you\u0026rsquo;ll be prompted to insert a USB key; just click cancel and choose whichever method you prefer instead. The same applies to mobile devices. Either way, you\u0026rsquo;ll now see a new button in the login window for using a key.\n","date":"January 14, 2026","externalUrl":null,"permalink":"/en/posts/authentik-two-factor-authentication/","section":"Posts","summary":"A guide to setting up two-factor authentication in Authentik using TOTP and WebAuthn, covering flows, stages, and security best practices.","title":"Setting up two-factor authentication in Authentik","type":"posts"},{"content":" Note If you found this article useful and would like to thank the author, you can do so via the corresponding link on boosty\nAs an administrator in Authentik, you can manually create and delete users, generate complex passwords for them, and set up their login rules using TOTP codes or WebAuthn devices. This is certainly a workable mechanism, but what if there are a lot of such users? Or even if we\u0026rsquo;re talking about some home use scenario, you simply want to automate the process so that you only deal with the management side of things. In this article, we\u0026rsquo;ll talk about how to set up such automation for user registration and invitations in Authentik.\nTip For this setup, and generally for Authentik to work correctly going forward, you should have already configured your mail server details in the .env environment variables file, from which notifications will be sent to both you and your users. You can verify the mail server is configured correctly with the simple command docker exec authentik_worker ak test_email your_email@domain.com\nNote The application settings described in this article are accurate as of the time of writing.\nNote The video guide linked below is accurate as of when it was created, but the configuration logic hasn\u0026rsquo;t changed.\nNote Starting with release 2026.5, Authentik has a dedicated Invitation Wizard right in the admin panel, which can speed up sending invitations without manually assembling flows/stages. The manual method below still works and gives you more control over the details - and it\u0026rsquo;s the one I show in this article.\nCreating a group for regular users # In the Authentik interface, go to Directory \u0026gt; Groups \u0026gt; New Group\nIn the window that appears, give our group a name. Since these will be regular users, we don\u0026rsquo;t toggle the Superuser Privileges switch.\nClick Create\nAnswering an unasked question - \u0026ldquo;why did I name the group so oddly, with the first word lowercase and the second capitalized?\u0026rdquo; - I\u0026rsquo;ll explain that the default group for admins is spelled exactly that way, authentik Admins. I\u0026rsquo;m just keeping the style consistent.\nCreating stages and flows # Email Stage # Go to Flows and Stages \u0026gt; Stages \u0026gt; Create\nIn the menu that appears, select Email Stage\nClick Next and in the next window set the necessary parameters: give the stage a name, an email subject, and the template that will be used. Click Finish\nCreating the invitation flow # Go to Flows \u0026gt; Create\nFill in and set the necessary parameters roughly as shown in the screenshot below. I enabled compatibility mode for better compatibility with password managers. In the Authentication field, I didn\u0026rsquo;t set any mandatory parameters. I did this intentionally - later on I\u0026rsquo;ll set a hard requirement for all users, without exception, to set up two-factor authentication.\nNow go to the Enrollment flow we created \u0026gt; Stage Bindings \u0026gt; Bind existing stage (as you probably guessed, you can also create stages from this menu by clicking Create and Bind Stage, but I think my approach is more illustrative).\nIn the menu that appears, fill it in following my screenshot. Select the existing stage default-source-enrollment-prompt, and set the processing order for this stage.\nNote Note that I have the evaluate when flow is planned toggle enabled. If you\u0026rsquo;re familiar with the topic, you can choose a different option.\nNow we need to make changes to the newly created stage. Click Edit Stage and select the data fields we need, which new users will need to fill in when registering.\nWe select the following values: name, email, password, repeat password. The username value is already selected by default. In the Validation Policy section, select the password complexity policy we created (you can read how to set password complexity values in the article on password recovery). Click Update\nNow let\u0026rsquo;s create a new stage binding for the flow: click Bind existing stage \u0026gt; default-source-enrollment-write, set the processing order, click Create.\nAs before, let\u0026rsquo;s make changes to the created stage \u0026gt; Edit Stage\nEnable the Create users as inactive option. This is needed so that after new users enter their data and register in the system, their account remains inactive until they confirm the action via email. For Group, select the authentik Users group we created. Be sure to select internal in the User type section.\nClick Bind existing stage once more, select email-account-confirmation, which we created earlier, set the processing order, click Create.\nYou can check the settings for this stage. Actually there isn\u0026rsquo;t much to edit here, we just make sure that the Activate pending users on success feature is enabled. If you haven\u0026rsquo;t configured mail via environment variables, deactivate the global settings toggle. New fields will appear that you\u0026rsquo;ll need to fill in with the corresponding values from your email provider.\nConfiguring default-authentication-flow # Go to Flows, select our authentication flow, in my case default-authentication-flow, go into the Stage Bindings menu, and make changes to the default-authentication-identification stage. Scroll all the way down, and in the Flow Settings menu under Enrollment Flow, select the newly created flow and click Update.\nLog out of our account and check the login menu (of course, all this should be done in incognito mode, and at minimum you need to clear your browser cookies).\nWe see that a new registration menu for new users has appeared.\nYou can test the menu\u0026rsquo;s functionality: have a new (test) user (you, in this case) register, receive a confirmation email, click the link in the email, and the rest is intuitive. If you did everything right, and the article\u0026rsquo;s author didn\u0026rsquo;t mess anything up (as sometimes happens), you now have a new user who created their own account, with a password matching the parameters and policies you set, and they\u0026rsquo;re now in the regular users group.\nSetting up user invitations in Authentik # We\u0026rsquo;ve now enabled new users to register on our Authentik instance themselves. But that\u0026rsquo;s too much freedom, letting any random passerby simply visit the Authentik site and register. We don\u0026rsquo;t want that, right? We want only select users to be able to register, and only by invitation. Or we could do a mass invitation mailing, but in any case, only the person we sent an invitation to will be able to register. Let\u0026rsquo;s set that up now.\nUser Write Stage # Go to Stages, create a new User Write Stage stage (due to a translation bug in application version 2025.10.3, which isn\u0026rsquo;t fully disabled, this stage is called \u0026ldquo;Этап записи пользователя\u0026rdquo; in my instance).\nClick Next. Set the necessary parameters: the stage name and its settings, plus which group new users will be placed into. Since we\u0026rsquo;re assuming we know who is registering, we can deactivate the Create users as inactive toggle.\nInvitation Stage # Let\u0026rsquo;s create another new stage, this time Invitation Stage (in my instance it\u0026rsquo;s called \u0026ldquo;Этап приглашения\u0026rdquo;).\nClick Next, give the stage a name. If the Continue flow without invitation toggle is enabled, disable it.\nNext, go to Flows \u0026gt; Create and set the necessary parameters. As before, I enable compatibility mode for password managers.\nNow go to the enrollment invitation flow we just created, and click Bind existing stage.\nHere we select the stage we created, set its processing order, and choose Evaluate when flow is planned instead of Evaluate when stage is run.\nClick Bind existing stage again and select default-source-enrollment-prompt, set its processing order, and choose Evaluate when flow is planned instead of Evaluate when stage is run.\nNow edit the default-source-enrollment-prompt stage and check that everything matches the screenshot. Basically, everything here is similar to the settings described at the beginning of this article.\nClick Bind existing stage again and select enrollment-invitation-write, set its processing order, and choose Evaluate when flow is planned instead of Evaluate when stage is run.\nOne last time, click Bind existing stage and select default-source-enrollment-login, set its processing order, and choose Evaluate when flow is planned instead of Evaluate when stage is run.\nCreating invitations # Now go to Directory \u0026gt; Invitations \u0026gt; Create\nIn the window that appears, give the invitation a name, specify how long it will be valid (you can effectively make it permanent), and decide whether it\u0026rsquo;s single use or reusable multiple times.\nClick Create.\nNow, to get the invitation link, just click the corresponding item in the dropdown menu, and we get our invitation link, which we can send to our users.\nNow anyone who receives such an invitation link, upon following it, will land on the new user registration menu, just like in the previous section.\nShutting the door on self-registration # Freedom is good, but in moderation. Let\u0026rsquo;s say we\u0026rsquo;ve registered everyone we need and aren\u0026rsquo;t expecting anyone else. Now we\u0026rsquo;ll strictly forbid new users from registering without our explicit control.\nGo to Stages \u0026gt; Create and create a new Deny Stage.\nClick Next, give our stage a name, and write the message that an uninvited guest will see if the wild idea strikes them to try registering on our Authentik instance.\nGo to Flows \u0026gt; main-page-enrollment, go to Bind existing stage. Select our Deny Stage. For the order number, choose any value, but with the mandatory condition that this stage is processed first - in my case that\u0026rsquo;s 0 - and choose Evaluate when flow is planned instead of Evaluate when stage is run, then click Create.\nNow, in incognito mode, let\u0026rsquo;s try registering on our Authentik instance, and if we did everything right, the user (whom we weren\u0026rsquo;t expecting) will get a rather unpleasant message.\nWith that, this article, which is essentially just a bunch of fun screenshots, can come to a close.\n","date":"January 13, 2026","externalUrl":null,"permalink":"/en/posts/authentik-enrollment-invitation/","section":"Posts","summary":"A guide to setting up the enrollment and invitation flow in Authentik: registering new users, invitations, stages, flows, and access policies.","title":"Setting up user enrollment and invitation processes in Authentik","type":"posts"},{"content":" Note If you found this article useful and would like to thank the author, you can do so via the corresponding link on boosty\nPassword recovery in Authentik # As an administrator (even for a homelab), first and foremost we must force (yes, force) our existing or future users to create complex passwords, rather than the simple passwords muggles love, like 12345 or password123. In this article, we\u0026rsquo;ll talk about how to do that, and we\u0026rsquo;ll also set up the ability for users to recover their passwords themselves (if you, as the administrator, want that).\nFor this setup, and generally for Authentik to work correctly going forward, you should have already configured your mail server details in the .env environment variables file, from which notifications will be sent to both you and your users. You can verify the mail server is configured correctly with the simple command docker exec authentik_worker ak test_email your_email@domain.com\nNote The application settings described in this article are accurate as of the time of writing.\nNote The video guide linked below is accurate as of when it was created, but the configuration logic hasn\u0026rsquo;t changed.\nCreating a policy for password complexity settings # Go to Customisation \u0026gt; Policies. Click the Create button. Select the Password Policy policy.\nFirst, give the policy a name. I prefer to name things in Authentik with a lowercase first letter, so the names don\u0026rsquo;t stand out from the rest, since Authentik\u0026rsquo;s default names start with a lowercase letter. Let\u0026rsquo;s say our policy will be called password-complexity. You\u0026rsquo;re free to use any name in whatever language is convenient for you. Scroll down and in the Static rules section, set the password complexity parameters - i.e., password length, number of characters, and so on.\nIn the Error Message section, specify the message that will be shown if a user sets a password that doesn\u0026rsquo;t comply with the policy you\u0026rsquo;ve configured.\nHere\u0026rsquo;s roughly what I ended up with:\nLeave all other fields in this menu at their defaults.\nClick Finish.\nCreating Flows and Stages # Now we need to create a Flow and Stages.\nIn the Flow and Stages section, select Stages. We need to create two stages.\nIdentification Stage # The first is user identification. Click Create \u0026gt; Identification Stage. Unfortunately, due to a bug in application version 2025.10.3, part of the menu is displayed in Russian for me, despite explicitly disabling automatic translation in the application, but I think you\u0026rsquo;ll get the idea.\nClick Next. In the next menu, give the stage a name, something like recovery-authentication-identification.\nFor the user fields, select Username and Email.\nLeave the rest of the menu sections alone for now - we won\u0026rsquo;t need them at this stage of the setup. Click Finish.\nThe next stage we need to create is password recovery with email confirmation.\nEmail Stage # In the Flow and Stages section, select Stages \u0026gt; Create \u0026gt; Email Stage.\nFor the email subject you can put something like \u0026ldquo;Password Recovery\u0026rdquo;. For the template, leave Password Reset. Click Finish.\nNow we need to create the password recovery flow.\nRecovery Flow # In Flow and Stages, select Flows \u0026gt; Create.\nSet the values following the screenshot below. I enabled compatibility mode - this improves compatibility with password managers and mobile devices.\nI left the other values at their defaults, but if you need additional customization for each individual flow, you\u0026rsquo;re free to make the corresponding changes.\nIn the Flows section, click the flow we just created - in my case it\u0026rsquo;s called recovery - and select Stage Bindings.\nClick Bind existing stage and select the recovery-authentication-identification stage we created earlier (as you probably guessed, you can also create stages from this menu by clicking Create and Bind Stage, but I think my approach is more illustrative).\nLeave the processing order for the stage at 0. Click Finish.\nBind another stage via Bind existing stage, and this time select the password recovery stage. I set the processing order to 10, because it\u0026rsquo;s more convenient to work with values like this, so there\u0026rsquo;s always room for new stages if needed later (and the developers do the same). Click Finish.\nBind another stage, this time an existing default one: Bind existing stage \u0026gt; default-password-change-prompt.\nAnd the last stage for this flow - Bind existing stage \u0026gt; default-password-change-write. Again, pay attention to the stage processing order.\nIn the end, we get the following picture:\nOnce again, pay attention to the stage processing order.\nNow, in this menu, select default-password-change-prompt and click Edit Stage. In the Validation Policies section, you need to select the previously created password-complexity policy and drag it into the menu on the right. Click Update.\nConfiguring the Authentication Flow # Go to the main Flows page, select default-authentication-flow \u0026gt; Stage bindings.\nOn this page, select Edit stage next to default-authentication-identification.\nTip In the Password Stage section, you can select default-authentication-password. As noted below: \u0026ldquo;If this option is enabled, the password field is shown on the same page rather than a separate one. This prevents username enumeration attacks.\u0026rdquo; This seems like a good setting, but if you later want to disable verification for local addresses (I\u0026rsquo;ll show how to do that in a future article), you\u0026rsquo;ll need to disable this option. So the decision is up to you.\nScroll all the way to the bottom of the menu, and in the Recovery Flow section, select the password recovery flow we created earlier.\nClick Update.\nIf you selected default-authentication-password in the Password Stage section, then in this flow\u0026rsquo;s main menu you need to remove the default-authentication-password stage. Otherwise it will conflict with the setting you chose.\nResult # Log out of our account, and at the bottom of the welcome page a note appears offering to recover the user\u0026rsquo;s login or password. If you configured showing the username and password on the same page, you\u0026rsquo;ll already see the password entry menu on this page.\nFrom here everything is fairly simple and intuitive. Choose the corresponding menu item, enter the email address of the user whose password you\u0026rsquo;ve forgotten, you\u0026rsquo;ll receive a notification by email offering to click a link, where Authentik will let you create a new password matching the complexity policy we set.\nNow your future users will be able to register in the application themselves or recover forgotten passwords.\n","date":"January 12, 2026","externalUrl":null,"permalink":"/en/posts/authentik-password-recovery/","section":"Posts","summary":"A detailed guide to setting up password recovery in Authentik, covering flows, stages, and policies, along with recommendations for protecting against username enumeration attacks.","title":"Setting up password recovery in Authentik","type":"posts"},{"content":"","date":"10 January 2026","externalUrl":null,"permalink":"/categories/containerization/","section":"Categories","summary":"","title":"Containerization","type":"categories"},{"content":"","date":"10 January 2026","externalUrl":null,"permalink":"/series/podman/","section":"Series","summary":"","title":"Podman","type":"series"},{"content":"","date":"10 January 2026","externalUrl":null,"permalink":"/tags/podman/","section":"Tags","summary":"","title":"Podman","type":"tags"},{"content":" Введение # Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nКогда речь заходит про контейнеры, девять человек из десяти по умолчанию имеют в виду Docker. Он действительно долгие годы был синонимом контейнеризации: docker run, docker-compose up и Dockerfile - это тот минимальный набор, который знает практически любой, кто хоть раз разворачивал сервис не на голом железе. Но у Docker есть архитектурная особенность, из-за которой у части сообщества, включая меня, к нему постепенно накопились вопросы - это постоянно работающий демон с root-правами.\nPodman - это попытка решить именно эту проблему, причём не косметически, а на уровне архитектуры. Это контейнерный движок без демона, с полноценным rootless-режимом из коробки и нативной интеграцией с systemd. В моем homelab он давно заменил Docker, и в этой статье я хочу разобрать, откуда Podman взялся, как он устроен внутри, чем принципиально отличается от Docker, и что такое поды, Quadlet и Podlet - термины, которые обычно и вызывают больше всего путаницы.\nОткуда взялся Podman # История у Podman не самая очевидная, и знать её полезно, чтобы понимать, почему проект устроен именно так.\nВсё началось в 2017 году внутри проекта CRI-O (container runtime для Kubernetes) с небольшой утилиты под рабочим названием kpod - её делали инженеры Red Hat, которым нужен был способ отлаживать и инспектировать контейнеры, созданные CRI-O, без необходимости поднимать полноценный Docker. Имя kpod никому в команде не нравилось, и через несколько месяцев разработки инструмент выделили в отдельный проект - библиотеку libpod, которая отвечала за управление подами и контейнерами без демона. А ещё через несколько месяцев, в начале 2018 года, вышел первый публичный релиз уже под новым именем - Podman, что расшифровывается как \u0026ldquo;POD MANager\u0026rdquo;.\nВажный нюанс: Podman - это не форк Docker. Это независимая реализация, написанная с нуля, которая при этом использует те же низкоуровневые стандарты и во многом те же компоненты экосистемы, что и Docker:\nrunc или crun - низкоуровневый OCI-runtime, который непосредственно запускает контейнер; conmon - лёгкий супервизор, следящий за процессом контейнера; containers/storage - библиотека для хранения образов и слоёв; containers/image - работа с реестрами и форматами образов. Сегодня Podman разрабатывается под эгидой Red Hat, входит в состав проекта containers на GitHub и является контейнерным движком по умолчанию в RHEL, Fedora, CentOS Stream и ряде других дистрибутивов, где Docker в принципе не поставляется из коробки уже несколько лет.\nДля каких задач нужен Podman # По сути Podman закрывает те же задачи, что и Docker - сборка образов, запуск контейнеров, работа с реестрами - но с прицелом на другие сценарии использования:\nлокальная разработка и тестирование контейнеризованных приложений; запуск контейнеров и подов на серверах и в homelab, особенно там, где хочется обойтись без демона; эксплуатация контейнеров без root-доступа, что критично для multi-tenant окружений; генерация Kubernetes-манифестов прямо из работающих контейнеров - удобно, если Kubernetes только планируется; замена Docker в CI/CD, где Podman может запускаться внутри самого CI-раннера без привилегированного демона. На практике чаще всего Podman выбирают для домашних лабораторий и небольших серверов с повышенными требованиями к безопасности, для edge-устройств с ограниченными ресурсами, и там, где Kubernetes уже используется или явно стоит в планах - генерация манифестов сильно упрощает миграцию.\nАрхитектура: почему нет демона # Ключевая архитектурная особенность Podman - daemonless-модель. У Docker есть dockerd, постоянно работающий в фоне процесс с root-правами, который принимает команды от клиента и управляет жизненным циклом всех контейнеров. У Podman такого процесса нет вообще: команда podman run напрямую, без посредников, вызывает conmon и runc/crun, которые и запускают контейнер как обычный дочерний процесс системы.\nИз этого вытекает несколько практических следствий:\nконтейнер Podman в ps виден как самостоятельный процесс, а не как что-то, спрятанное внутри демона - это заметно упрощает отладку; если что-то упало в одном контейнере, это не затрагивает остальные и уж тем более не требует перезапуска общего демона; пропадает единая точка отказа: не станет демона - не станет и всех контейнеров разом, как иногда бывает с Docker после сбойного обновления dockerd. systemd воспринимает такие процессы естественно, без обходных путей вроде docker run внутри ExecStart - об этом подробнее поговорим в разделе про Quadlet. Rootless-контейнеры и сеть # Rootless-режим в Podman - не костыль поверх существующей архитектуры, а то, ради чего проект во многом и затевался. Контейнер можно запустить от обычного, непривилегированного пользователя, и при этом внутри контейнера у процесса всё равно будет \u0026ldquo;свой\u0026rdquo; root - просто это не настоящий root хостовой системы.\nТехнически это реализовано через:\nuser namespaces - подмену UID/GID внутри контейнера на непривилегированные диапазоны на хосте; subuid/subgid - диапазоны идентификаторов, которые администратор выделяет пользователю для этой подмены (/etc/subuid, /etc/subgid); сетевой стек в user space, который не требует привилегий на хосте. Тут стоит сделать отдельную ремарку про сеть, потому что она за последние пару лет заметно изменилась. Раньше rootless-сеть в Podman почти всегда означала slirp4netns - рабочее, но довольно медленное решение. Начиная с Podman 5.x в качестве современной замены продвигается pasta - она заметно быстрее, полноценно поддерживает IPv6 и, что особенно приятно, \u0026ldquo;отражает\u0026rdquo; сетевую конфигурацию хоста прямо в контейнер вместо классического NAT. В актуальных версиях Podman pasta уже используется как бэкенд для rootless-сети по умолчанию, а поддержка slirp4netns в новых релизах постепенно сворачивается. Если у вас старый конфиг с явным указанием slirp4netns - самое время свериться с man podman-network для своей версии и по возможности перейти на pasta.\nИтог такого подхода: даже если контейнер скомпрометируют, атакующий окажется не в root-окружении хоста, а в изолированном namespace обычного пользователя - потенциальный ущерб принципиально меньше.\nЧем Podman отличается от Docker # Сравнение по ключевым параметрам # Критерий Docker Podman Архитектура Клиент-демон (dockerd) Без демона Права демона root демона нет Rootless Есть, но требует отдельной настройки и имеет ограничения Полноценный режим \u0026ldquo;из коробки\u0026rdquo; Интеграция с systemd Через обходные пути Нативная (Quadlet) Kubernetes-манифесты Нужны сторонние инструменты Встроенная генерация YAML Поды Нет как первичной сущности Есть, как в Kubernetes CLI Docker CLI Совместим с Docker CLI Совместимость с Docker # Пожалуй, лучшая новость для тех, кто переходит с Docker - переучиваться почти не придётся. CLI Podman намеренно сделан максимально похожим:\nalias docker=podman После такого алиаса подавляющее большинство привычных команд просто продолжает работать:\npodman run -d -p 8080:80 nginx podman build -t myapp . podman pull docker.io/library/redis podman push myapp registry.example.com/myapp Формат Dockerfile тоже поддерживается без каких-либо изменений - Podman умеет собирать образы из обычных Dockerfile, дополнительно предлагая свой более гибкий формат Containerfile (по сути то же самое, просто другое имя файла).\nПоды (Pods) в Podman # Что такое под # Под (pod) - это группа из одного или нескольких контейнеров, которые:\nразделяют один сетевой namespace, то есть общий IP-адрес и общее пространство портов; при желании могут совместно использовать IPC-namespace; логически представляют собой одно приложение, которое удобно запускать и останавливать как единое целое. Концепция полностью заимствована из Kubernetes, и это не случайность, а осознанное архитектурное решение - Podman изначально проектировался так, чтобы модель локальной разработки была максимально близка к тому, как приложение потом будет вести себя в кластере. Типичный под - это, например, контейнер с приложением, контейнер с reverse-proxy перед ним и sidecar-контейнер для логирования или метрик, которые вместе образуют один логический сервис.\nПример: создаём под руками # podman pod create --name web-pod -p 8080:80 podman run -d --pod web-pod nginx podman run -d --pod web-pod busybox sleep infinity Все контейнеры внутри web-pod получают один общий IP-адрес и видят друг друга через localhost, как процессы на одной машине - можно смело обращаться друг к другу по 127.0.0.1:\u0026lt;порт\u0026gt; без настройки отдельной docker-сети, как пришлось бы делать в Docker.\nИз практических плюсов такого подхода: сетевое взаимодействие внутри пода становится тривиальным, конфигурация ближе к модели Kubernetes, а сами контейнеры логически группируются, что удобно и для мониторинга, и для последующей миграции.\nГенерация Kubernetes-манифестов # Отдельная сильная сторона Podman - умение прямо из работающего пода сгенерировать готовый Kubernetes YAML:\npodman generate kube web-pod \u0026gt; pod.yaml Это позволяет собрать и обкатать архитектуру приложения локально на одной машине, а потом перенести конфигурацию в кластер без переписывания с нуля - Podman в этом смысле неплохо работает как \u0026ldquo;локальный Kubernetes\u0026rdquo; для разработки и тестирования.\nPodman и systemd # Podman нативно умеет интегрироваться с systemd - и делать это можно двумя способами.\nПервый, более старый - генерация unit-файла из уже созданного контейнера или пода:\npodman generate systemd --name nginx --files --new Команда создаёт .service-файл, который можно положить в systemd-юниты и управлять контейнером стандартными systemctl start/stop/enable. Этот способ рабочий, но требует, чтобы контейнер уже существовал, и плохо подходит для декларативного описания инфраструктуры \u0026ldquo;с нуля\u0026rdquo;.\nВторой, современный и рекомендуемый способ - Quadlet.\nЧто такое Quadlet # Quadlet - это встроенный в Podman механизм, который позволяет описывать контейнеры, поды, сети, volume\u0026rsquo;ы и образы декларативно, обычными systemd unit-файлами специального формата. systemd на старте сам транслирует такие файлы в полноценные .service-юниты и запускает их через Podman - вручную ничего генерировать не нужно.\nВсего Quadlet поддерживает несколько типов файлов:\nРасширение Что описывает .container отдельный контейнер .pod под (группу контейнеров) .volume именованный volume .network сеть .image образ, который нужно заранее подтянуть .build сборку образа из Containerfile .kube развёртывание из Kubernetes YAML (podman kube play) .artifact OCI-артефакт Файлы размещаются в одном из стандартных путей, в зависимости от того, нужен ли системный (root) или пользовательский (rootless) сервис:\n/etc/containers/systemd/ # системные квадлеты, root ~/.config/containers/systemd/ # пользовательские, rootless Пример .container-файла # [Container] Image=docker.io/library/nginx:latest PublishPort=8080:80 Volume=nginx-data:/usr/share/nginx/html:Z [Service] Restart=always [Install] WantedBy=multi-user.target После создания файла достаточно перечитать конфигурацию systemd и запустить сервис:\nsystemctl daemon-reload systemctl start nginx.container Дальше это уже полноценный systemd-сервис: автозапуск при загрузке системы через [Install], единый журнал через journalctl -u nginx.container, управление зависимостями через стандартные After=/Requires=. Для homelab, где нет и не планируется Kubernetes, но есть systemd - это, на мой взгляд, оптимальный способ держать инфраструктуру контейнеров.\nPodlet: помощник в написании Quadlet-файлов # Писать .container-файлы руками не всегда удобно, особенно когда под рукой уже есть рабочая команда docker run или docker-compose.yml, которые не хочется переписывать с нуля. Для этого есть отдельный инструмент - Podlet (не путать с Quadlet, это разные вещи, хотя названия и похожи).\nPodlet - самостоятельная утилита на Rust, которая не входит в состав самого Podman, но плотно с ним используется. Она умеет генерировать Quadlet-файлы тремя способами: из команды podman run (или docker run - синтаксис почти идентичен), из существующего compose-файла, и даже из уже запущенного контейнера, пода, сети или volume\u0026rsquo;а через podlet generate.\npodlet podman run -d -p 8080:80 nginx Команда выше выведет в консоль готовый .container-файл со всеми нужными секциями - остаётся сохранить его в правильную директорию. Для compose-файлов Podlet умеет либо разбивать сервисы на отдельные .container-файлы, либо собирать их в один .pod вместе с сопутствующими контейнерами - в зависимости от того, что ближе к исходной архитектуре приложения.\nНа практике Podlet особенно полезен именно на этапе миграции с Docker Compose: не нужно вручную разбираться в синтаксисе Quadlet-секций - достаточно скормить существующий docker-compose.yml, а дальше уже донастроить сгенерированный файл под себя.\nКогда стоит выбирать Podman # Из моего собственного опыта, Podman особенно оправдан, если:\nдля вас важны безопасность и rootless-режим по умолчанию, а не как опция, которую нужно отдельно допиливать; на сервере и так используется systemd, и хочется управлять контейнерами теми же привычными командами systemctl, а не отдельным демоном; Kubernetes уже используется или явно в планах - переносить конфигурацию через podman generate kube удобнее, чем писать манифесты с нуля; нужна daemonless-архитектура без единой точки отказа; вы строите homelab или self-hosted инфраструктуру и не хотите, чтобы всё держалось на одном привилегированном процессе. Заключение # Podman - это не \u0026ldquo;Docker, но бесплатно\u0026rdquo; и не клон ради клона. Это отдельная, довольно зрелая на сегодняшний день реализация контейнерного движка, которая решает конкретные архитектурные проблемы Docker: убирает демон с root-правами, делает rootless-режим полноценным, а не опциональным, и нативно встраивается в systemd через Quadlet.\nДля homelab и небольших серверов переход с Docker на Podman у меня лично не потребовал почти никаких компромиссов - CLI совместим, Dockerfile работает как есть, а взамен я получил меньше точек отказа и намного более прозрачную интеграцию с systemd. Если вы давно присматриваетесь к Podman, но не решались - лучший способ узнать, подходит ли он вам, это просто попробовать на одном не самом критичном сервисе.\nПолезные ссылки:\nОфициальный сайт Podman Репозиторий Podman на GitHub Документация Podman Документация по Quadlet (man podman-systemd.unit) Репозиторий Podlet на GitHub ","date":"10 January 2026","externalUrl":null,"permalink":"/posts/what-is-podman/","section":"Posts","summary":"Podman - контейнерный движок без демона, ориентированный на безопасность и rootless-режим. Разбираем историю проекта, архитектуру, отличия от Docker, поды, Quadlet и Podlet - и когда есть смысл переходить.","title":"Podman: современная альтернатива Docker","type":"posts"},{"content":"","date":"6 January 2026","externalUrl":null,"permalink":"/tags/community/","section":"Tags","summary":"","title":"Community","type":"tags"},{"content":"Серия статей о новостях и событиях из мира Homelabbing, Open Source, Linux, виртуализации, сетевых технологий и self-hosting. Здесь собраны обзоры важных релизов, обновлений популярных проектов, новых инструментов и других событий, которые могут быть интересны энтузиастам домашних лабораторий и самостоятельного развёртывания сервисов.\n","date":"6 January 2026","externalUrl":null,"permalink":"/posts/news/","section":"Posts","summary":"Серия статей о новостях и событиях из мира Homelabbing, Open Source, Linux, виртуализации, сетевых технологий и self-hosting. Здесь собраны обзоры важных релизов, обновлений популярных проектов, новых инструментов и других событий, которые могут быть интересны энтузиастам домашних лабораторий и самостоятельного развёртывания сервисов.\n","title":"News","type":"posts"},{"content":"","date":"6 January 2026","externalUrl":null,"permalink":"/series/news/","section":"Series","summary":"","title":"News","type":"series"},{"content":"","date":"6 January 2026","externalUrl":null,"permalink":"/categories/open-source/","section":"Categories","summary":"","title":"Open Source","type":"categories"},{"content":"","date":"6 January 2026","externalUrl":null,"permalink":"/tags/open-source/","section":"Tags","summary":"","title":"Open Source","type":"tags"},{"content":" Всем привет! Сегодня поговорим о не очень позитивных вещах. Речь пойдет о проблемах open-source сообщества, а лично я вижу очень, очень плохую тенденцию, которая в будущем может привести к очень, очень нехорошим вещам.\nСподвигла меня к этой статье новость уже 2026 года\nПроблемы добровольческого участия в Debian - команда по защите данных осталась без участников # Суть новости:\nКоманда Data Protection Team проекта Debian, которая отвечает за обработку запросов о данных, соблюдение приватности и взаимодействие с внешними сторонами, осталась полностью без участников - все три члена добровольно ушли из команды одновременно. Debian Mailing Lists\nПочему это важно: # Это показывает реальную проблему усталости и нехватки волонтёров в крупных open source-проектах:\nкритические административные функции остаются без поддержки; обязанности переходят на ограниченных по времени других ключевых участников (например, лидера проекта); без новых добровольцев у Debian нет устойчивого механизма для вопросов о защите данных. Debian Mailing Lists Контекст:\nНехватка активных участников даже в таком крупном и зрелом проекте, как Debian, отражает более широкую проблему в экосистеме open source: рост технических обязательств без роста сообщества, готового вкладывать своё время и усилия. reddit.com\nOpen WebUI: ужесточение лицензионных формулировок и контроль бренда # В репозитории Open WebUI был принят коммит , который не затрагивает функциональность проекта, а полностью сосредоточен на переработке формулировок в лицензии и сопутствующих текстах. Изменения касаются юридической стороны использования проекта, а именно - условий распространения, ответственности и упоминания бренда Open WebUI.\nКлючевой момент - усиление требований к сохранению оригинального названия и идентичности проекта при распространении и модификации. Фактически это шаг в сторону более жёсткого контроля над тем, как проект может использоваться третьими лицами, особенно в коммерческих и полукоммерческих сценариях.\nЭтот кейс хорошо иллюстрирует одну из системных проблем open source в 2025 году: разработчики всё чаще пытаются защитить свои проекты не кодом, а лицензиями. В результате появляются гибридные или «псевдо-open source» модели, которые формально открыты, но накладывают дополнительные ограничения, вызывая споры в сообществе и снижая совместимость с классической open source-экосистемой.\nС одной стороны, разработчики говорят, что так они просто борются с недобросовестной конкуренцией, когда нехорошие люди чужое выдают за свое, с другой стороны, сообщество начинает беспокоится.\nТоже самое было с моделью upstream у CentOS. \u0026ldquo;Всякие\u0026rdquo; Oracle и OpenSuse брали дистрибьютив, нагло ставили туда свой бренд и продавали за деньги корпоративному сектору. Чем закончилось - все знают. Ну правда, Red Hat получило, конкретно в данном случае, огромную порцию не совсем заслуженного хейта от сообщества.\nPlanka - теперь не совсем «open source»: особая лицензия и практика распространения # Проект Planka - веб-приложение для управления задачами в стиле Kanban - позиционируется как self-hostable инструмент, похожий на Trello. Однако его лицензия отличается от классических свободных лицензий: код распространяется под Fair Use License и отдельной Pro/Enterprise License, а не под признанными свободными лицензиями вроде MIT или GPL. GitHub\nЧто это означает: # Исходный код всегда доступен для просмотра (source available), и приложение можно развернуть самостоятельно. GitHub При этом юридические условия лицензии ограничивают способы использования и распространения, особенно в коммерческих сценариях. GitHub Это не классический open source в понимании OSI/Open Source Definition: проект ввёл собственные ограничения, которые делают его ближе к source available / fair-code модели, нежели к свободному ПО. GitHub Почему это важно для экосистемы open source: # Planka - не единичный случай. Это тенденция\nGoogle усиливает безопасность Android через Developer Verification # В августе 2025 года компания Google объявила о запуске новой системы верификации разработчиков Android, призванной повысить безопасность платформы, особенно в части установки приложений вне официального магазина Google Play. Android Developers Blog\nПо данным официального блога разработчиков Android, исследования показали, что количество вредоносных приложений, распространяемых через прямые загрузки (sideloading), в 50 раз превышает число угроз из Google Play. Android Developers Blog\nВ ответ Google планирует с 2026 года требовать, чтобы все приложения, устанавливаемые на сертифицированные Android-устройства, были связаны с проверенной и подтверждённой личностью разработчика. Это означает, что анонимность, которую использовали злоумышленники для многократного выпуска вредоносного ПО под разными именами, будет устранена через централизованную идентификацию. Android Developers Blog\nЭто расширение существующих требований в Google Play не включает проверку содержания приложений - компания проверяет лишь личность разработчика, а не сам код. GIGAZINE\nПри этом пользователи по-прежнему смогут устанавливать приложения из любых источников, но для этого разработчики должны пройти верификацию через новую Android Developer Console. Android Developers Blog\nПилотный запуск начнётся осенью 2025 года, открытая регистрация - в марте 2026-го, а обязательное требование - сначала в Бразилии, Индонезии, Сингапуре и Таиланде, с последующим глобальным развёртыванием в 2027 году и дальше. Malwarebytes\nВ итоге это бьет по сторонним магазинам приложений типа F-Droid.\nESR и критика Codes of Conduct в open source # В сентябре 2025 года известный автор и основной теоретик open source Эрик С. Рэймонд (ESR) опубликовал в социальной сете X (твиттере) резкий комментарий по поводу современных Codes of Conduct (CoC) в open source-проектах. Он назвал их «катастрофой», результатом «десяти лет драмы и идиотизма», и призвал отказаться от тяжеловесных кодексов поведения в проектах. X (formerly Twitter)(\u0026ldquo;деятельность организации X запрещена на территории РФ\u0026rdquo;)\nОсновная мысль ESR - формальные CoC, по сути, не решают реальных проблем и даже создают новые. Он считает, что такие документы слишком бюрократичны, легко вооружаются против участников и отвлекают сообщества от технической работы и прямого взаимодействия между людьми. Shuji Sado\nЭта критика отражает широкую дискуссию в сообществе open source: многие разработчики считают, что агрессивные и формальные правила поведения снижает свободу сотрудничества и превращают проекты в политизированные пространства, где больше внимания уделяется соблюдению CoC, чем качеству кода или реальному общению. news.ycombinator.com\nNextcloud против Google: проблема с загрузкой файлов на Android # В мае 2025 года команда Nextcloud публично разоблачила ситуацию, при которой приложение Nextcloud Files для Android потеряло возможность загружать произвольные файлы (не только фото и видео) из‑за действий Google в Google Play Store. Речь шла о ключевом разрешении Android (MANAGE_EXTERNAL_STORAGE), которое позволяло приложению иметь доступ ко всем файлам на устройстве. Полгода работы без него фактически ограничили функциональность - пользователи могли загружать только медиафайлы, а не документы, архивы и прочие файлы, что подорвало основное обещание Nextcloud как self‑hosted облака. Nextcloud\nNextcloud утверждал, что этот отказ был необоснованным с точки зрения безопасности, поскольку аналогичные приложения продолжают иметь полный доступ, и что Google просто «обладает платформой и даёт себе преимущество». Команда многократно обращалась в Google с просьбой вернуть разрешение, но первые ответы были стандартными и непродуктивными. В своём блоге Nextcloud прямо заявил: «все вы имеете худший клиент Nextcloud потому что этого хотел Google». Nextcloud\nВ середине мая 2025 года Google восстановил доступ к файлам для приложения, и обновление с возвращённой функцией полноценных загрузок готовилось к выпуску. Это стало результатом публичного давления и обратной связи сообщества. Однако инцидент стал наглядным примером, так называемой, gatekeeping‑политики Big Tech, когда владеющая платформой компания может ограничивать возможности конкурирующих приложений, даже если они технически безопасны и важны для пользователей. arstechnica.com\nСпор вокруг Rust и C в ядре Linux - угроза «неподдерживаемой сложности» # В начале февраля 2025 года в сообществе Linux разгорелся острый конфликт вокруг попыток расширить использование Rust внутри ядра Linux и обеспечивать его взаимодействие с существующим C‑кодом. Проблема вспыхнула после того, как поддерживающий интеграцию Rust в Linux патч, позволяющий Rust‑драйверам вызывать низкоуровневые C‑функции ядра (например, API для DMA), столкнулся с резкой критикой со стороны одного из основных мейнтейнеров ядра, Кристофа Хеллвига. Он назвал идею смешения Rust и C в ядре «рак - не из‑за Rust как языка, а из‑за сложности, которую создаёт кросс‑язычная кодовая база» и заявил, что это снижает “поддерживаемость” и ухудшает читаемость проекта. The Register+1\nХеллвиг настаивал, что интерфейсы ядра должны оставаться на C, а все Rust‑обёртки и взаимодействия должны быть ограничены отдельными слоями, чтобы не размывать границы кода и не заставлять мейнтейнеров C‑подсистем разбираться в Rust‑слое. Противники этой позиции утверждают, что такая конфронтация тормозит эволюцию ядра и игнорирует пользу Rust в плане безопасности памяти. The Register\nЭтот конфликт отражает более широкую проблему open source‑экосистемы в 2025 году: рост технической сложности и разногласий по поводу инструментов и языков, когда попытки модернизации сталкиваются с культурой консерватизма, упреками в «ит‑драме» и разногласиями о том, как должны развиваться крупные проекты вроде Linux. The Register\nОтставка мейнтейнера Nouveau и токсичность сообщества Linux‑ядра # В начале 2025 года разработчик Karol Herbst, один из мейнтейнеров open‑source драйвера Nouveau для Linux (обратная реализация драйвера NVIDIA), официально ушёл с роли мейнтейнера ядра из‑за того, что назвал сообщество токсичным и неприязненным. Его заявление появилось вместе с отказом от обязанности поддерживать код Nouveau в upstream‑ядре Linux. Phoronix\nHerbst прямо указал, что последней каплей стало то, как в обсуждении ядра была употреблена фраза “we are the thin blue line” («мы - тонкая синяя линия»), которую он счёл политически и культурно чувствительной и вредной, особенно в контексте нынешней социальной ситуации в США. Он заявил, что такие высказывания не способствуют инклюзивности и уважительному взаимодействию в сообществе, и в таких условиях он не может продолжать участие. Phoronix\nЭта история вызвала бурную реакцию в сообществе разработчиков: часть людей считает, что технические дебаты не должны переходить в культурные и политические конфликты, а другие говорят, что попытки игнорировать влияние фраз и поведения на разные группы - это тоже проблема. Обсуждение в комментариях Hacker News показывает, насколько глубоки разногласия о том, где проходит граница между техническими обсуждениями и культурными / социальными контекстами в больших open source‑проектах. Hacker News\nПочему это важно: # Этот случай иллюстрирует, что в 2025 году в open source всё чаще всплывают вопросы не только про код, но и про сообщество - как взаимодействуют люди, какие культурные и социальные ожидания применяются, и что конфликты вокруг языка и поведения могут привести к потере ключевых участников. Это не только технический, но и человеческий вызов для устойчивости крупных проектов. Phoronix\nAsahi Linux: основатель уходит, проект переходит к коллективному руководству # В феврале 2025 года команда Asahi Linux официально объявила о том, что её основатель и лидер Hector Martin (известный как marcan) ушёл с позиции руководителя проекта. Вместо одной ключевой фигуры проект переходит к коллективному управлению - в руководство вошли семь активных разработчиков, включая специалистов по ядру Linux, графике и аудио. Asahi Linux+1\nВ посте на официальном блоге Asahi Linux подчёркивается, что проект должен стать более устойчивым и независимым от одного человека: «никто, даже очень талантливый, не должен держать на себе весь проект». Это переход к более формальной и разделённой ответственности, что важно для долгосрочной поддержки большой base code, особенно с учётом сложностей с поддержкой Apple Silicon и постоянной работой с upstream‑ядром Linux. Asahi Linux\nЭто решение возникло на фоне выгоревшего руководителя и растущего давления, с которым сталкиваются разработчики open source - проблемы включали конфликт с ядром Linux относительно Rust‑кода, сложные технические задачи и интенсивную нагрузку сообщества. FOSS Force\nПочему это важно: # Этот кейс отражает широкую проблему зрелых open source‑проектов в 2025 году: зависимость от ключевых людей, риск выгорания лидеров и необходимость распределённой модели управления для устойчивого развития. Это не только технический переход, но и организационный вызов, с которым сталкиваются многие крупные проекты, пытаясь сохранить активность и эффективность в условиях сложного взаимодействия с upstream‑сообществами и интенсивными требованиями пользователей. Asahi Linux\nAutomattic сокращает вклад в WordPress из‑за конфликта с WP Engine # В январе 2025 года компания Automattic, наиболее известная как владелец WordPress.com и сооснователь проекта WordPress, официально объявила о сокращении своих спонсируемых вкладов в развитие WordPress. Вместо тысяч часов вклада в ядро и экосистему, Automattic решила ограничить своё участие примерно 45 часами в неделю, сопоставимыми с вкладом другого крупного хоста - WP Engine, и сосредоточить силы на собственных коммерческих продуктах вроде WordPress.com, Jetpack, WooCommerce и других. Automattic+1\nКомпания объяснила этот шаг существенными затратами времени и ресурсов на судебное противостояние с WP Engine, а также критикой и давлением со стороны части сообщества, которые требовали отставки руководства Automattic. Automattic Авторы заявления подчёркивали, что хотят «пересмотреть, переосмыслить и стратегически спланировать», как их усилия могут лучше служить будущему платформы. Automattic\nЭтот эпизод вскрыл серьёзный конфликт в рамках одного из крупнейших open source‑проектов: когда компания, на протяжении более чем двух десятилетий являющаяся ключевым участником, публично снижает вклад под давлением внутренних и внешних факторов. Это вызвало дебаты о равноправии участия, ответственности крупных организаций и устойчивости проектов, живущих за счёт вклада сообщества. lwn.net\nМассовая отставка модераторов NixOS из‑за вмешательства руководящего комитета # В сентябре 2025 года большая часть команды модераторов официального форума NixOS объявила о немедленной отставке в знак протеста против постоянного вмешательства Steering Committee (SC) - руководящего комитета проекта - в работу модерации. NixOS Discourse\nВ своём открытом заявлении модераторы заявили, что SC неоднократно пытался ставить под вопрос их решения, сдерживать их работу и даже влиять на состав команды модераторов, вплоть до попыток отменить решения и назначить собственных людей. Они подчеркнули, что существующая Конституция проекта не даёт эффективных механизмов защиты от такого вмешательства, поэтому продолжать работу в таких условиях они больше не могут. NixOS Discourse\nАвторы обращения также призвали к большей прозрачности, ответственности и реформе управления, чтобы создать систему с реальными сдержками и противовесами между SC и другими командами, включая тех, кто отвечает за модерацию и техническое руководство. Многие участники сообщества поддержали эти требования и указывают на то, что конфликт отражает глубокие проблемы с управлением, доверием и культурой общения в крупном open source‑проекте. NixOS Discourse\nПочему это важно: # Этот случай показывает, что проблемы в open source‑экосистеме далеко не только про код - организационная структура, власть и доверие внутри сообществ могут быть такими же критичными факторами, как технические вызовы или лицензирование. Когда базовые механизмы управления не гарантируют независимость и баланс интересов, это может привести к потере людей, которые делают проект живым и устойчивым. NixOS Discourse\nВывод: кризис людей и структуры в open source 2025 года # События 2025 года показывают, что проблемы open source давно вышли за рамки чисто технических вопросов. Крупные проекты сталкиваются с хронической нехваткой добровольцев (Debian, Asahi Linux), выгоранием ключевых участников (Nouveau, Asahi), и с конфликтами между старой культурой разработки и новыми языками и инструментами (Rust vs C в Linux).\nКроме того, структурные и организационные проблемы - от токсичной среды в ядре Linux до вмешательства Steering Committee в NixOS - угрожают устойчивости сообществ, которые формально открыты, но на практике зависят от нескольких людей, готовых выполнять критические функции.\nЮридические и лицензионные ограничения (Planka, Open WebUI) показывают, что контроль над проектом всё чаще реализуется через правила и лицензии, а не через сообщество. Крупные платформы (Android, Nextcloud, WordPress) всё активнее используют силу экосистемы, чтобы контролировать доступ и вклад, что ограничивает свободу разработки и распределение ответственности.\nВ сумме это отражает системный вызов open source в 2025 году: проекты становятся сложнее, ответственность растёт, а механизмы управления, поддержки и мотивации людей часто не успевают за технологическими и социальными реалиями. Без внимания к структурам, прозрачности и заботе о людях сама идея открытого кода рискует превратиться в технически открытые, но человечески уязвимые проекты.\nГлавный урок: открытый код остаётся важным, но его будущее зависит не только от технологий, а от устойчивых, справедливых и заботливых сообществ, способных удерживать ключевых участников и поддерживать баланс между свободой, безопасностью и управляемостью # ","date":"6 January 2026","externalUrl":null,"permalink":"/posts/open-source-crisis-2025/","section":"Posts","summary":"В 2025 году open source столкнулся с проблемами, выходящими за рамки кода: от выгорания и отставок ключевых участников до лицензионных ограничений и давления крупных платформ. Разбираем, что происходило с крупными проектами и как это отражает системные вызовы для всей экосистемы.","title":"Open Source в кризисе: ключевые события 2025 года","type":"posts"},{"content":"","date":"6 January 2026","externalUrl":null,"permalink":"/tags/software-development/","section":"Tags","summary":"","title":"Software Development","type":"tags"},{"content":" Karakeep vs Linkwarden: comparing self-hosted bookmark and link archive managers # Introduction # Self-hosted bookmark managers are an important part of a modern homelab and personal knowledge infrastructure. They let you not just save links, but archive content, protecting it from disappearing, blocking, and changes to the original sites.\nIn this article we\u0026rsquo;ll take a detailed look at Karakeep and Linkwarden - two popular open-source solutions for self-hosting. The material is aimed at:\nhomelab owners; DevOps and system administrators; technical writers and researchers; users who want control over their data. By the end of the article you\u0026rsquo;ll have a clear idea of which tool to choose for your particular scenario.\nBrief overview of the projects # Karakeep - a universal knowledge store # Karakeep is a universal knowledge store. It combines:\nbookmarks; notes; images; PDF files; video; web page archives. The project emphasizes search, indexing, and categorization of large volumes of data. Karakeep is often seen as a hybrid of a bookmark manager, a personal knowledge base, and a media archive.\nLinkwarden # Linkwarden is primarily a bookmark manager with powerful page archiving. Its core idea is to save a link so that it stays accessible even if the original site disappears.\nMain focus:\naccurate web page preservation; convenient reading (reader view); long-term link archive; shared use of collections. Karakeep vs Linkwarden comparison table # Criterion Karakeep Linkwarden Solution type Universal knowledge store Bookmark manager with archiving Main focus Search, notes, media, AI Bookmarks and web page saving Self‑host Yes Yes License AGPL‑3.0 AGPL‑3.0 Data storage File storage + built-in services PostgreSQL + object storage Page archiving Yes Yes (key feature) PDF / images Yes Yes Video Yes Limited Reader‑view Basic Advanced Full-text search Yes (Meilisearch) Yes (Meilisearch) AI tags and analysis Yes (OpenAI / Ollama) Yes (Ollama) Collaboration Limited Yes Shared collections No / limited Yes Browser extension Yes Yes Mobile apps Yes Yes Deployment complexity Low Medium Suitable for homelab Excellent Good Functional differences # Working with data # Karakeep stores not just links, but full content:\nuploaded files; images; PDFs; video; notes. This makes it convenient for building a personal knowledge base or \u0026ldquo;digital archive.\u0026rdquo;\nLinkwarden, on the other hand, concentrates on links and web pages. It excels at preserving a page\u0026rsquo;s appearance, structure, and content, but doesn\u0026rsquo;t aim to be a universal store for everything.\nSearch and indexing # Karakeep places a strong emphasis on search:\nfull-text indexing; fast search through file contents; tags, categories, filters; AI automation (summaries, tags, content analysis). Linkwarden also supports search, but it\u0026rsquo;s more oriented toward:\npage titles; URLs; tags; text of saved pages. AI capabilities # Karakeep can use local or cloud LLMs for:\nautomatic tagging; content analysis; improved search. This is especially useful if you have a large library of links and documents.\nLinkwarden deliberately remains a more classic tool without AI logic.\nTechnical side and operations # Deployment # Karakeep:\nsimpler to install; doesn\u0026rsquo;t require PostgreSQL; suits Docker, Podman, Kubernetes; feels good in a homelab and LXC containers. Linkwarden:\nrequires PostgreSQL; infrastructure is more complex; better suited to a permanent server with database backups. Performance and resources # Karakeep is generally lighter on resources and starts faster, especially in a minimal configuration.\nLinkwarden can consume more resources due to:\nthe database; generating page archives; screenshots and PDFs. User experience # Karakeep:\noriented toward search and navigation; suited for large collections; the interface is less \u0026ldquo;read-it-later,\u0026rdquo; but more universal. Linkwarden:\nconvenient for reading; strong reader view; logical for everyday work with bookmarks and articles. What to choose and in which scenarios # Choose Karakeep if: # you need a unified archive (bookmarks + files + notes); fast search across all content matters to you; you\u0026rsquo;re interested in AI capabilities; you\u0026rsquo;re building a personal knowledge base or homelab storage. Choose Linkwarden if: # your main task is bookmarks and articles; quality page archiving matters; you need a reader view and reading mode; you\u0026rsquo;re planning collaboration or shared collections. Summary and recommendations # Karakeep and Linkwarden solve a similar problem - saving and managing links - but with different philosophies.\nKarakeep is a universal knowledge hub that combines bookmarks, files, notes, and search in one interface. It\u0026rsquo;s especially well suited for homelab, personal knowledge bases, and users who value flexibility and scalability.\nLinkwarden is a specialized tool for archiving web pages and articles. It\u0026rsquo;s excellent for read-it-later scenarios, research work, and shared use of collections.\nQuick pick # For homelab, personal archiving, and experimenting with AI - Karakeep. For neatly storing articles and links with an emphasis on reading - Linkwarden. Both projects are actively developed and deserve attention. The optimal choice doesn\u0026rsquo;t come down to \u0026ldquo;better or worse,\u0026rdquo; but rather to how exactly you work with information.\n","date":"January 5, 2026","externalUrl":null,"permalink":"/en/posts/linkwarden-vs-karakeep/","section":"Posts","summary":"A detailed comparison of Karakeep and Linkwarden - self-hosted bookmark and link archive managers. We break down features, differences, architecture, a comparison table, and recommendations for homelab and DevOps.","title":"Best Bookmark Manager: Linkwarden or Karakeep","type":"posts"},{"content":"","date":"January 5, 2026","externalUrl":null,"permalink":"/en/tags/karakeep/","section":"Tags","summary":"","title":"Karakeep","type":"tags"},{"content":"","date":"January 5, 2026","externalUrl":null,"permalink":"/en/tags/linkwarden/","section":"Tags","summary":"","title":"Linkwarden","type":"tags"},{"content":" Вступление # Мне часто пишут или просят сделать обзор на то или иное приложение. Как правило это конечно связано с тем, что у просящего что-то не получается, но необходимо отметить, что иногда просят показать и актуальные, современные приложения. И здесь есть один важный момент. Приложения выходят часто, идеи в них заложены интересные. Одно но, лично я хочу посмотреть как приложение и его автор покажут себя на дистанции. Ну чтобы не получилось как это часто бывает с опенсорсом. Автор устал, у автора есть оплачиваемая работа, приложение заброшено.\nСегодня я хочу рассказать о приложениях, которые вышли в 2025 году, сразу привлекли внимание сообщества и на данный момент не показывают признаков, что их забросят.\nPangolin # Pangolin - это open‑source платформа для удалённого доступа и проксирования с акцентом на безопасность (zero‑trust). Главная цель проекта - предоставить самостоятельно размещаемую альтернативу Cloudflare Tunnel / Twingate / Zero‑Trust VPN, позволяющую безопасно публиковать внутренние сервисы в интернет и обеспечивать доступ к приватным ресурсам через браузер или клиентские приложения. ✔️ Комбинирует обратный прокси (reverse proxy, под капотом Traefik) и Zero‑Trust VPN / WireGuard‑туннели\n✔️ Имеет панель управления, аутентификацию и доступ по ролям\n✔️ Предназначен как для self‑hosted инсталляций, так и для управления через управляющий облачный сервис Pangolin Cloud Репозиторий содержит TypeScript‑код, интерфейсы Dashboard UI и серверную логику для управления доступом и маршрутизацией.\n⚙️ Основные механизмы и архитектура # 🛠️ Компоненты # 📌 Pangolin Server - центральный сервер с UI и API, который управляет доступом к ресурсам. 📌 Newt - туннельный агент (site connector), который устанавливает защищённое соединение между удалённой сетью/хостом и Pangolin Server посредством WireGuard‑подобного туннеля (часто в пользовательском пространстве). 📌 Clients - пользователи или машины, которые подключаются к сервисам через Pangolin, получают доступ к “Private Resources”. 🔑 Аутентификация и авторизация # Pangolin поддерживает:\nВстроенная аутентификация с UI Интеграция с внешними IdP (OAuth2/OIDC) - например, Authentik или Keycloak. Авто‑провиженинг пользователей при логине через внешний IdP. Правила доступа к ресурсам можно настраивать по:\nIP / диапазону CIDR URL‑пути Ролям/группам ASN‑правилам Правилам на уровне портов и протоколов (TCP/UDP). 🌐 Сетевые механизмы # 🚀 WireGuard‑подобный туннель обеспечивает безопасную связь между сервером и удалёнными сайтами/клиентами. 🚀 Zero‑Trust Network Access (ZTNA) - доступ определяется не по наличию VPN‑соединения, а по политике доступа к каждому ресурсу. 🚀 Magic DNS - резолвинг дружелюбных имен внутри приватной сети при подключении клиента. 📌 Применение # Pangolin подходит для:\n✅ Публикации внутренних веб‑сервисов (UI, API, панели и пр.) через браузер без прямого открытия портов\n✅ Обеспечения доступа к SSH, RDP, базам данных или другим внутренним сервисам\n✅ Объединения нескольких сетей/офисов под единую безопасную инфраструктуру\n✅ Zero‑Trust Remote Access (ZTNA) вместо традиционного VPN 👍 Плюсы # 🔐 Безопасность и Zero‑Trust\nГранулярный доступ на уровне ресурсов, не даёт полного доступа ко всей сети. Поддержка внешних OAuth2/OIDC IdP. 🌍 Гибкие сетевые возможности\nПоддержка туннелей через NAT/файрволлы (Newt). Клиенты для Windows/Mac/Linux. 📊 UI + управление\nПанель управления с доступом, логами, настройками. Тонкая настройка правил доступа. 🔄 Развитое сообщество и частые обновления\nАктивные релизы с новыми функциями (firewall, ACL, DNS, magic DNS и др.). 👎 Минусы и ограничения # ⚠️ Сложность\nИзначальная настройка может быть непроста для новичков (DNS, туннели, firewall). ⚠️Зависимость от конфигурации\nНеправильная конфигурация может привести к уязвимостям (например, CVE по аутентификации при insecure‑config).\n⚠️ Исходный проект всё ещё развивается\nНекоторым компонентам (например, мобильным клиентам) требуется доработка и планируется релиз позже. ⚠️ DNS‑зависимость и внешний доступ\nЕсли DNS/серверные компоненты недоступны, сервисы могут перестать резолвиться (как показано в практических случаях). ⚠️ Лицензия\nОсновной код под AGPL‑3 (обязывает открывать изменения при публичном использовании), коммерческие варианты с другими условиями тоже существуют. Pangolin - отличная самохостинговая альтернатива Cloudflare Tunnels и классическим VPN‑решениям с Zero‑Trust подходом, если нужна продвинутая маршрутизация, аутентификация и доступ по ролям без прямого проброса портов в сеть. Papra # 📌 Что такое Papra # Papra - это облачная и open‑source платформа для управления и архивирования документов. Она помогает организовать, хранить и быстро находить любые файлы в одном месте, избавляя от «хаоса» в папках и разбросанных по разным сервисам данных. Основные идеи:\nцентрализованное хранение документов; удобная организация с помощью тегов и «организаций»; мощный поиск; расширяемость через API и интеграции; возможность self‑host (самостоятельно запускать на собственном сервере). 🎯 Для чего оно нужно # Papra решает классические задачи цифрового документооборота:\n✔️ Централизованное хранение - все документы в одном месте вместо сотен папок на диске. ✔️ Организация и метаданные - теги, правила автоматического тегирования, структуры «организаций» для команд. ✔️ Поиск и быстрый доступ - полнотекстовый поиск по документам позволяет находить нужное за секунды. ✔️ Интеграции и автоматизация - API, Webhooks, CLI, email‑импорт и SDK позволяют встроить Papra в рабочие процессы. ✔️ Архивирование - подходит как для повседневного использования, так и для долгосрочного хранения важных документов. 👤 Целевая аудитория # 🔹 Частные пользователи # хранение личных документов: сканы, заявления, контракты, страховки, квитанции и др.; удобное хранение и поиск; доступ с разных устройств. 🔹 Малые и средние команды # общий доступ к документам между сотрудниками; организация по проектам или группам; аудит действий и управление доступом. 🔹 Профессионалы и компании # архивирование юридически важных документов; интеграция с другими системами через API и webhooks; контроль пользовательской активности и аудит. 🔹 Тех‑энтузиасты и self‑host‑пользователи # запуск сервиса на собственной инфраструктуре; контроль над данными, без облачного провайдера. 🎉 Плюсы # ✅ Централизованное управление документами\nВсе документы и метаданные собраны в одном месте, легко организуются и находятся. ✅ Мощный поиск\nБыстрый полнотекстовый поиск - даже по содержимому загруженных файлов. ✅ Гибкая организация\nТеги, автоматические правила классификации, иерархии «организаций».\n✅ Инструменты для разработчиков\nAPI, CLI, SDK, webhooks позволяют автоматизировать задачи или интегрировать Papra в другие сервисы. ✅ Email‑импорт\nМожно присылать документы на уникальный email, и Papra автоматически сохранит вложения. ✅ Open‑source и self‑host\nМожешь запустить Papra на собственном хосте бесплатно. ✅ Прозрачность и приватность\nPapra позиционирует себя как этичное и независимое решение, без продажи данных. ⚠ Минусы / ограничения # ❗ Требует настройки (если self‑host)\nЧтобы использовать Papra на своём сервере, нужны базовые навыки Docker и администрирования. ❗ Базовые функции ещё развиваются\nНекоторые расширенные функции, например обмен документами или запросы на загрузку, могут быть пока не реализованы или в разработке. ❗ Платный план для крупных объёмов\nВ облачном варианте есть бесплатный тариф с ограниченным хранилищем и участниками, а для больших организаций требуется платный план.\n❗ Не узкоспециализирован DMS\nЭто не крупная корпоративная система документооборота с продвинутыми workflow, версия контроля версий, сложными правами - по сравнению с крупными корпоративными DMS. 📊 Итог # Papra - это удобный современный инструментарий для управления, поиска и архивирования документов, который может использоваться как личный архив, так и в командах. Он хорошо подойдет тем, кто хочет:\n✔ централизовать все документы;\n✔ иметь мощный поиск и метаданные;\n✔ иметь контроль над данными через self‑host;\n✔ интегрировать управление документами в свои процессы.\nЕсли тебе нужно корпоративное DMS‑решение с расширенными бизнес‑workflow, то Papra может быть хорошей основой, но возможно потребуется интеграция с другими системами\nTinyAuth # 🚀 Что такое TinyAuth # TinyAuth - это лёгкое приложение для аутентификации (Login/Access control), которое помогает защитить веб‑сервисы и приложения простым способом: оно показывает экран логина перед доступом к защищённому сервису и проверяет пользователя. Основная идея TinyAuth - простота:\nминимальные зависимости (нет сложной базы данных, интерфейсов, большого количества конфигураций), конфигурация через переменные окружения, интеграция с популярными прокси (например, Traefik, Nginx, Caddy), поддержка базового входа (OAuth, TOTP двухфакторная аутентификация и др.). Это решение гораздо проще, чем такие комплексные продукты, как Authentik, Keycloak или другие IAM/SSO‑системы, которые ориентированы на корпоративные сети и крупные проекты. 👥 Кому подходит TinyAuth # Целевая аудитория:\n✅ HomeLab‑энтузиасты, которые хотят быстро защитить свои самохостинг‑сервисы (например: веб‑панели, домашние сервисы, личные дашборды). ✅ Люди, которые ищут минималистичное и простое решение без сложной инфраструктуры.\n✅ Тех, кто использует обратные прокси (Traefik, Nginx, Caddy) и хочет добавить простую проверку логина перед доступом к сервисам.\n👎 Не лучший выбор для больших организаций или систем с:\nсложным управлением пользователями, LDAP/AD интеграцией, многоуровневыми правами доступа, динамическим обновлением пользователей без перезапуска. ⚙️ Как это работает # TinyAuth обычно разворачивается как контейнер (например, Docker) и стоит между пользователем и защищаемым сервисом:\nЗапрос пользователя попадает на TinyAuth. TinyAuth отображает экран входа. После успешной аутентификации - запрос продолжается к сервису. Конфигурация - через переменные окружения, например список пользователей, секреты, настройки OAuth и т.п. Сессии - статeless (без сервера с базой), что делает систему простой, но есть ограничение: сервер не может автоматически завершить сессию так, чтобы она \u0026ldquo;истекла\u0026rdquo; на сервере. 👍 Плюсы TinyAuth # ✔️ Простота и лёгкость\nНастраивается без сложных конфигураций. Не требует отдельной базы данных. Минимум зависимостей. ✔️ Хорошая интеграция с обратными прокси\nРаботает \u0026ldquo;из коробки\u0026rdquo; с Traefik, Nginx, Caddy и прочими серверами. ✔️ Поддержка двухфакторной аутентификации\nМожно добавить 2FA (например TOTP), что повышает уровень безопасности по сравнению с простым логином‑паролем. ✔️ Опенсорс и лёгкость для хомелабов\nИдеально подходит для защиты внутренних сервисов у любителей домашних серверов. 👎 Минусы и ограничения # ⚠️ Не предназначен для крупных проектов\nОтсутствует полноценная система управления пользователями. Нет поддержки LDAP/Active Directory и сложных прав доступа. ⚠️ Статeless (ограниченные сессии)\nСервер не может \u0026ldquo;истекать\u0026rdquo; сессии как полноценный аутентификатор; управление сессией - упрощённое. ⚠️ Плохая масштабируемость на корпоративном уровне\nЕсли вам нужны десятки групп/ролей, централизованное управление и динамическое обновление пользователей - TinyAuth может быть неудобен.\n⚠️ Требует перезапуска для обновления конфигураций\nЛюбое изменение списка пользователей/прав доступа часто требует рестарта. 📌 Где стоит использовать # ✨ Защитить домашние веб‑сервисы (домашний Proxmox/AdGuard/Nextcloud).\n✨ В связке с Traefik/Nginx для базовой защиты.\n✨ Когда нужна простая аутентификация без корпоративных IAM‑решений.\n🛑 Когда лучше не использовать TinyAuth # ❌ Если нужна корпоративная IAM выстроенная по стандартам.\n❌ Если нужен централизованный LDAP/AD доступ или SSO для массы сервисов.\n❌ Если у вас много пользователей и сложные права/группы.\n📌 Альтернативы (чаще используются в более сложных средах) # Authentik - гибкий IAM/SSO, LDAP/AD‑поддержка. Keycloak - мощная корпоративная платформа SSO/OAuth. Authelia - reverse‑proxy‑ориентированный аутентификатор. OAuth‑Proxy/OAuth2‑Proxy - лёгкие прокси для OAuth авторизации. Zerobyte # 📌 Что такое Zerobyte # Zerobyte - это система для планирования, выполнения, мониторинга и восстановления резервных копий. Он создан поверх популярного инструмента Restic, который отвечает за сам процесс создания резервных копий (шифрование, дедупликация и т. д.). Zerobyte добавляет к Restic:\nсовременный веб‑интерфейс (GUI) для управления; планировщик задач резервного копирования; мониторинг статуса и журналов; гибкие политики хранения и шифрования;\nвсё это удобно настраивается без ручного запуска команд. 🔐 Backups шифруются и сжимаются, хранятся на разных типах хранилищ (локальный диск, облако, S3‑совместимый сервис и др.). 🧠 Основные возможности # ✔️ Автоматическое резервное копирование с планировщиком и расписаниями. ✔️ Шифрование и компрессия данных с помощью Restic. ✔️ Поддержка разных источников: локальные директории, NFS, SMB, WebDAV и др. ✔️ Множество вариантов хранилищ для сохранения бэкапов:\nлокальные каталоги; S3‑совместимые хранилища; облачные провайдеры через rclone (Google Drive, Dropbox и др.). ✔️ Веб‑интерфейс для мониторинга всех задач и восстановления файлов. 📦 Может запускаться через Docker + Docker Compose (стандартный способ). 👤 Целевая аудитория # Zerobyte ориентирован прежде всего на:\n🎯 Home‑lab‑энтузиастов и self‑hosters - людей, которые сами управляют своими серверами, NAS или домашними кластерами и хотят удобный интерфейс для бэкапов. 🎯 Малые компании и ИТ‑специалисты, которым нужна простая система резервного копирования без сложной корпоративной инфраструктуры. 🎯 Любых пользователей, которым Restic сам по себе слишком неудобен через CLI, но нравится его функциональность. 👍 Плюсы Zerobyte # ✅ Простой веб‑интерфейс, который облегчает работу с резервным копированием (не нужно CLI). ✅ Гибкие настройки планирования и политики хранения. ✅ Шифрование и дедупликация благодаря Restic. ✅ Поддержка разных хранилищ, включая облачные через rclone. ✅ Может выступать как централизованное место бэкапов для множества данных. 👎 Минусы и ограничения # ⚠️ Ещё в ранней стадии разработки (0.x) - могут быть изменения API, баги и нестабильности. ⚠️ Зависит от Docker - нет официальной поддержки запуска без контейнеров. ⚠️ Некоторые функции (например, резервное копирование баз данных, остановка сервисов перед бэкапом) не встроены - их нужно организовать отдельно скриптами. ⚠️ Его не всегда считают готовым для крупных корпоративных сред (скорее подойдёт для небольших инсталляций). 🧩 В чем отличие от Restic # Restic сам по себе - это CLI‑инструмент для резервного копирования, мощный, но без графического интерфейса и планировщика. Zerobyte берёт Restic и:\n📍 добавляет удобство: GUI, расписания, мониторинг;\n📍 делает управление более доступным для non‑CLI‑пользователей. 🧪 Пример сценария использования # Запустить Zerobyte через Docker на домашнем сервере. Через веб‑интерфейс добавить источники данных: домашние папки, NFS/SMB‑шары. Настроить резервное хранилище (например, S3‑совместимое или облачное через rclone). Создать расписание автоматических бэкапов. В случае сбоя восстановить данные через веб‑интерфейс. ","date":"2 January 2026","externalUrl":null,"permalink":"/posts/best-apps-2025/","section":"Posts","summary":"В этой статье мы собрали самые интересные self-hosted приложения, которые появились в 2025 году. От медиасерверов и инструментов для продуктивности до систем для безопасности и автоматизации - разберём, что стоит попробовать и почему.","title":"Лучшие self-hosted приложения 2025 года — личная подборка","type":"posts"},{"content":" Docker vs Podman vs Kubernetes: подробное сравнение контейнерных технологий # Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nКонтейнеризация давно стала стандартом де-факто для доставки и эксплуатации приложений, но под общим словом \u0026ldquo;контейнеры\u0026rdquo; на самом деле скрываются инструменты совершенно разного уровня. Docker и Podman - это движки для запуска и сборки контейнеров на одной машине. Kubernetes - это оркестратор, который управляет кластером таких машин. Их часто путают или сравнивают напрямую, хотя это, строго говоря, разные весовые категории. В этой статье я подробно разберу архитектуру, накладные расходы и области применения всех трёх, чтобы было понятно, что с чем на самом деле имеет смысл сравнивать.\n1. Как соотносятся эти решения # Решение Уровень Основное назначение Docker Container runtime + tooling Упаковка, запуск и управление контейнерами Podman Container runtime (без демона) Альтернатива Docker с упором на безопасность Kubernetes Оркестрация контейнеров Управление кластерами и жизненным циклом приложений Важно сразу зафиксировать: Kubernetes - не замена Docker или Podman, а надстройка над ними. Кластер Kubernetes всё равно где-то внутри использует container runtime (containerd, CRI-O, а исторически - и сам Docker через dockershim, который, к слову, из Kubernetes давно выпилили). Поэтому корректное сравнение выглядит так: Docker vs Podman - это выбор runtime для одной машины, а Kubernetes - отдельный вопрос о том, нужна ли вам оркестрация вообще.\n2. Docker # 2.1 Архитектура # Docker работает по классической клиент-серверной схеме:\nDocker CLI - то, с чем взаимодействует пользователь; dockerd - демон, который постоянно работает в фоне с root-правами и реально управляет контейнерами; containerd и runc - более низкоуровневые компоненты, которые непосредственно запускают процессы. Цепочка вызовов выглядит так: Docker CLI → dockerd → containerd → runc → контейнер. Ключевая деталь здесь - именно dockerd: он есть всегда, работает с максимальными привилегиями и является единой точкой, через которую проходят вообще все операции с контейнерами.\n2.2 Основные возможности # сборка образов через Dockerfile; Docker Compose для мультиконтейнерных приложений; Docker Hub и совместимость с любыми OCI-реестрами; собственные volume- и network-драйверы; самая широкая на сегодняшний день экосистема готовых образов, плагинов и обучающих материалов. 2.3 Накладные расходы # С точки зрения ресурсов, главная плата за удобство Docker - постоянно работающий демон. Даже без единого запущенного контейнера dockerd уже занимает какое-то количество памяти (обычно в районе 50-150 МБ, в зависимости от версии и конфигурации) и добавляет лишний слой системных вызовов между командой пользователя и реальным запуском процесса.\nС точки зрения безопасности - dockerd по умолчанию работает от root, а значит, теоретическая компрометация демона потенциально даёт компрометацию всего хоста. Rootless-режим у Docker существует и постепенно становится удобнее, но по-прежнему требует отдельной настройки и имеет больше практических ограничений (например, по сети и по некоторым функциям хранилища), чем rootless в Podman, где это базовый режим работы, а не надстройка.\n2.4 Преимущества # низкий порог входа - огромное количество готовых туториалов, компоуз-файлов и образов \u0026ldquo;из коробки\u0026rdquo;; максимальная совместимость с существующими CI/CD-пайплайнами и облачными сервисами; зрелая экосистема инструментов (Docker Desktop, Docker Scout и так далее). 2.5 Недостатки # root-демон как потенциальная единая точка отказа и атаки; rootless-режим менее зрелый, чем у Podman; Docker Desktop для коммерческого использования в компаниях определённого размера требует платной подписки - это стоит учитывать при выборе для рабочих задач, хотя сам движок Docker Engine остаётся open-source. 3. Podman # 3.1 Архитектура # Podman устроен принципиально иначе - без демона:\nPodman CLI → conmon → runc/crun → контейнер\nКаждый контейнер запускается как обычный дочерний процесс текущего пользователя, без постоянно висящего в фоне посредника. Это не косметическое отличие, а основа всей архитектуры: нет демона - нет единой точки отказа и единой цели для атаки.\n3.2 Основные возможности # rootless-контейнеры по умолчанию, а не как опция; полная поддержка Dockerfile и собственного формата Containerfile; Podman Compose для запуска обычных docker-compose.yml; нативная генерация systemd-юнитов через Quadlet - подробнее об этом у меня есть отдельная статья; CLI, практически совместимый с Docker (alias docker=podman в большинстве случаев работает без сюрпризов). 3.3 Накладные расходы # Ресурсов Podman в простое потребляет меньше именно потому, что нечему работать в фоне - демона попросту нет. С точки зрения безопасности контейнеры по умолчанию изолированы через user namespaces, современная rootless-сеть построена на pasta (актуальная замена устаревающему slirp4netns), а сам Podman хорошо подходит для multi-tenant окружений, где несколько пользователей на одной машине не должны иметь возможность влиять на контейнеры друг друга.\n3.4 Преимущества # повышенная безопасность за счёт daemonless-архитектуры и полноценного rootless-режима; меньше накладных расходов, что особенно заметно на серверах и VPS с ограниченными ресурсами; полностью open-source без каких-либо коммерческих ограничений на использование. 3.5 Недостатки # заметно меньше обучающих материалов и готовых рецептов, чем у Docker - многое приходится гуглить или разбираться по документации; Podman Compose исторически менее зрелый и не на 100% совместим с полным синтаксисом Docker Compose; часть Docker-ориентированных инструментов и GUI из коробки рассчитана именно на сокет dockerd, и с Podman требует либо совместимого API-сокета (podman system service), либо доработки напильником. 4. Kubernetes # 4.1 Архитектура # Kubernetes - это распределённая система оркестрации, а не runtime сам по себе. У него принципиально другой масштаб: не один хост, а кластер узлов.\nControl Plane отвечает за состояние всего кластера:\nAPI Server - точка входа для всех запросов; Scheduler - решает, на каком узле запустить под; Controller Manager - следит, чтобы фактическое состояние соответствовало желаемому; etcd - распределённое хранилище состояния кластера. Worker Nodes непосредственно выполняют рабочую нагрузку:\nkubelet - агент, который управляет подами на узле; container runtime (containerd, CRI-O - именно на этом уровне Kubernetes и обращается к тому, что мы обсуждали выше); kube-proxy - сетевые правила и балансировка внутри кластера. 4.2 Основные возможности # self-healing - автоматический перезапуск упавших подов; горизонтальное и вертикальное автомасштабирование; service discovery и встроенная балансировка нагрузки; rolling updates без простоя; полностью декларативная конфигурация через YAML-манифесты. 4.3 Накладные расходы # Здесь Kubernetes честно проигрывает по простоте: даже одноузловой кластер (тот же k3s или minikube) требует заметно больше ресурсов, чем Docker или Podman - реалистичный минимум для комфортной работы начинается от 1-2 ГБ RAM, etcd довольно требователен к дисковым IOPS, а сама установка и последующее сопровождение кластера - отдельная область знаний, а не пара команд в терминале.\n4.4 Преимущества # фактический индустриальный стандарт оркестрации; высокая масштабируемость и отказоустойчивость; де-факто обязательное решение для serious production и high availability. 4.5 Недостатки # явный overkill для одиночного сервера или домашней лаборатории; высокий порог входа - concepts вроде Ingress, Services, ConfigMaps, RBAC нужно осваивать отдельно; избыточная сложность для небольших нагрузок, где с задачей прекрасно справится один сервер с Podman и Quadlet-юнитами. 5. Прямое сравнение # 5.1 Docker vs Podman # Критерий Docker Podman Демон Есть (dockerd, root) Нет Rootless Ограниченно, требует настройки Полноценный режим по умолчанию Безопасность Средняя Высокая Совместимость CLI/Dockerfile Эталонная Почти полная Потребление ресурсов в простое Выше Ниже Интеграция с systemd Через обходные пути Нативная (Quadlet) Для серверов и homelab, где нет жёсткой необходимости именно в экосистеме Docker Desktop, Podman выглядит логичной и, на мой взгляд, более безопасной заменой.\n5.2 Docker/Podman vs Kubernetes # Критерий Docker / Podman Kubernetes Назначение Запуск контейнеров Оркестрация кластера Масштаб Один хост Множество узлов Автовосстановление Частичное (через Restart= в systemd/Compose) Полноценное, встроенное Порог входа Низкий Высокий 6. Типовые сценарии использования # Сценарий Рекомендуемое решение Homelab Podman или Docker - зависит от привычек Одиночный VPS Podman (меньше накладных расходов, rootless по умолчанию) CI/CD раннеры Docker или Podman - оба варианта распространены Enterprise production с несколькими серверами Kubernetes Edge / IoT устройства Podman - меньше потребление ресурсов Микросервисы с автомасштабированием Kubernetes 7. Итоговые выводы # Когда выбирать Docker: нужен максимально быстрый старт, вы учитесь или ведёте desktop-разработку, важна максимальная совместимость с готовыми туториалами и существующими пайплайнами - у Docker в этом смысле до сих пор нет равных по объёму материалов.\nКогда выбирать Podman: речь про сервер или VPS, где повышенные требования к безопасности и хочется rootless-контейнеры без танцев с бубном, а инфраструктура и так завязана на systemd - для homelab и self-hosting лично я считаю Podman более осмысленным выбором по умолчанию.\nКогда выбирать Kubernetes: нужно реальное масштабирование, высокая доступность и production-кластер из нескольких узлов, либо вы изначально строите cloud-native архитектуру. Для одного сервера дома Kubernetes почти всегда избыточен - тут Podman с Quadlet-юнитами закроет задачу проще и с меньшими накладными расходами.\nНикакого универсального победителя тут нет - это три инструмента для разных по масштабу задач, и выбор должен определяться реальным сценарием использования, а не тем, что \u0026ldquo;все так делают\u0026rdquo;.\nПолезные ссылки:\nОфициальный сайт Docker Официальный сайт Podman Официальный сайт Kubernetes ","date":"22 December 2025","externalUrl":null,"permalink":"/posts/docker-podman-kubernetes/","section":"Posts","summary":"Сравниваем Docker, Podman и Kubernetes: архитектура, безопасность, накладные расходы и реальные сценарии применения - от homelab до production-кластеров.","title":"Docker vs Podman vs Kubernetes: подробное сравнение контейнерных технологий","type":"posts"},{"content":"","date":"22 December 2025","externalUrl":null,"permalink":"/tags/it/","section":"Tags","summary":"","title":"IT","type":"tags"},{"content":"","date":"22 December 2025","externalUrl":null,"permalink":"/tags/kubernetes/","section":"Tags","summary":"","title":"Kubernetes","type":"tags"},{"content":" Quadlet и Podlet в Podman # Контейнеры без Kubernetes и Docker Compose # Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nКогда я только переезжал с Docker Compose на Podman, у меня в голове была небольшая путаница с двумя очень похожими по звучанию терминами - Quadlet и Podlet. Звучат почти одинаково, оба связаны с контейнерами, оба всплывают в одном контексте - и первое время я, чего греха таить, путал их местами. Разница на деле принципиальная: Quadlet - это встроенный в Podman формат описания контейнеров через systemd, а Podlet - отдельная утилита, которая помогает эти описания генерировать, а не писать руками с нуля. В этой статье разберу оба инструмента подробно, покажу примеры конфигураций и сравню такой подход с привычным Docker Compose.\n1. Quadlet # Что такое Quadlet # Quadlet - это встроенный в Podman механизм, позволяющий описывать контейнеры, поды, сети, volume\u0026rsquo;ы и образы декларативно, обычными systemd unit-файлами специального формата. При старте системы systemd сам транслирует такие файлы в полноценные .service-юниты и запускает их через Podman - ничего генерировать вручную не требуется, достаточно daemon-reload.\nQuadlet появился как развитие идеи podman generate systemd, только вместо императивного \u0026ldquo;сгенерируй юнит из уже запущенного контейнера\u0026rdquo; здесь всё наоборот - вы декларативно описываете желаемое состояние, а systemd приводит систему к этому состоянию сам, в том числе после перезагрузки хоста.\nТипы Quadlet-файлов # Расширение Что описывает .container отдельный контейнер .pod под - группу контейнеров с общей сетью .volume именованный volume .network сеть .image образ, который нужно заранее подтянуть .build сборку образа из Containerfile .kube развёртывание из Kubernetes YAML (podman kube play) .artifact OCI-артефакт Где размещаются Quadlet-файлы # /etc/containers/systemd/ - системные (root) юниты; ~/.config/containers/systemd/ - пользовательские, rootless-юниты. Пример .container-файла # [Container] Image=docker.io/library/nginx:latest ContainerName=nginx PublishPort=8080:80 Volume=nginx-data:/usr/share/nginx/html:Z [Service] Restart=always [Install] WantedBy=multi-user.target Пример .pod-файла # Если нужно объединить несколько контейнеров в один под с общей сетью, для этого есть отдельный тип юнита .pod:\n# web-pod.pod [Pod] PublishPort=8080:80 А сами контейнеры затем подключаются к этому поду через ссылку на .pod-файл:\n# web-app.container [Container] Image=myapp:latest Pod=web-pod.pod [Service] Restart=always # web-cache.container [Container] Image=docker.io/library/redis:latest Pod=web-pod.pod [Service] Restart=always Все контейнеры, привязанные к одному поду, разделяют общий сетевой namespace и видят друг друга через localhost - точно так же, как если бы под создавался вручную командой podman pod create.\nУправление Quadlet-юнитами # systemctl daemon-reload systemctl enable --now nginx.container systemctl status nginx.container journalctl -u nginx.container -f С этого момента контейнер - полноценный systemd-сервис: автозапуск при загрузке через [Install], управление зависимостями через After=/Requires=, единый журнал через journalctl, штатный Restart= вместо самодельных скриптов-обвязок.\nПреимущества Quadlet # нативная интеграция с systemd - никаких обходных путей и самодельных обвязок; автозапуск и восстановление после сбоя штатными средствами systemd; управление зависимостями между сервисами (например, \u0026ldquo;запускать после того, как поднялась сеть\u0026rdquo;); единое централизованное логирование через journalctl; полная поддержка rootless-режима. Ограничения Quadlet # требует systemd - на системах без него (некоторые embedded-дистрибутивы, часть Alpine-окружений) не работает; рассчитан на один хост - никакой кластеризации; не заменяет Kubernetes, если вам действительно нужны autoscaling, service discovery на несколько узлов и HA. 2. Podlet # Что такое Podlet # Podlet - это отдельная утилита на Rust, которая не входит в состав самого Podman, но плотно с ним используется. Задача Podlet простая и полезная: избавить вас от необходимости писать Quadlet-секции руками, если под рукой уже есть рабочая команда podman run/docker run или файл docker-compose.yml.\nВажно: Podlet не создаёт контейнеры и не является рантаймом - он только генерирует текст готового Quadlet-файла, который затем нужно сохранить в нужную директорию и подхватить через systemctl daemon-reload.\nГенерация из команды # Самый простой сценарий - взять существующую команду запуска и просто заменить podman run/docker run на podlet podman run:\npodlet podman run -d -p 8080:80 -v nginx-data:/usr/share/nginx/html:Z --name nginx nginx:latest На выходе - готовый .container-файл со всеми нужными секциями [Container], [Service], [Install], который остаётся сохранить в ~/.config/containers/systemd/ или /etc/containers/systemd/.\nГенерация из docker-compose.yml # Это, пожалуй, самый практически полезный режим при миграции с Docker Compose:\npodlet compose docker-compose.yml Podlet разберёт файл и, в зависимости от структуры проекта, либо создаст по отдельному .container-файлу на каждый сервис, либо сгруппирует связанные сервисы в один .pod вместе с сопутствующими .container-файлами - так, чтобы результат максимально соответствовал исходной архитектуре compose-проекта.\nГенерация из уже работающего объекта # Если контейнер, под, сеть или volume уже созданы вручную и работают, Podlet может \u0026ldquo;снять\u0026rdquo; с них Quadlet-конфигурацию:\npodlet generate container nginx Удобно, если вы сначала быстро подняли что-то командой в терминале, чтобы проверить, работает ли оно, а потом решили закрепить результат уже декларативно.\nЗачем нужен Podlet на практике # резко упрощает миграцию с Docker и Docker Compose - не нужно вручную разбираться в синтаксисе всех секций Quadlet; снижает число ошибок при ручном написании unit-файлов (забытый [Install], неверная секция Volume= и подобное); ускоряет сам процесс перехода - для типового проекта результат Podlet чаще всего нужно только слегка донастроить, а не писать с нуля. 3. Quadlet и Podlet вместе # Проще всего запомнить разницу так: Quadlet - это формат, который выполняется, а Podlet - это инструмент, который его пишет за вас. Они не конкурируют и не заменяют друг друга - это разные слои одного и того же процесса.\nDocker Compose / podman run │ ▼ Podlet ← генерирует Quadlet-файлы │ ▼ Quadlet ← декларативный формат │ ▼ systemd ← превращает Quadlet в .service и запускает │ ▼ Podman ← реально запускает контейнеры/поды На практике типичный рабочий процесс выглядит так: берёте существующий docker-compose.yml, прогоняете его через podlet compose, получаете набор .container/.pod-файлов, кладёте их в ~/.config/containers/systemd/, делаете daemon-reload - и с этого момента всё живёт как обычные systemd-сервисы.\n4. Сравнение с Docker Compose # Критерий Docker Compose Quadlet (+ Podlet) Требует демон Да Нет Rootless Ограниченно По умолчанию Автозапуск при старте системы Через обходные пути (restart: always + сторонний init) Нативно, через systemd [Install] Интеграция с systemd Отсутствует Полная Централизованные логи Через docker compose logs Через journalctl, вместе со всеми остальными сервисами системы Формат конфигурации YAML (docker-compose.yml) INI-подобные systemd-юниты Один хост Да Да Отдельно стоит понимать: Quadlet - это не прямая замена Docker Compose один в один, а скорее иной подход к тому же результату - вместо одного YAML-файла, который парсит отдельный инструмент (docker compose/podman-compose), вы получаете набор systemd-юнитов, которые распознаёт сама операционная система. Для тех, кто и так привык управлять сервисами через systemctl, это выглядит естественнее, чем держать в системе параллельный слой оркестрации compose-файлов.\n5. Практические сценарии # Homelab. Nextcloud, медиасерверы (Jellyfin, Plex), reverse proxy (Traefik, Caddy, nginx), мониторинг (Prometheus, Grafana) - типичный набор self-hosted сервисов, которые прекрасно живут как Quadlet-юниты и переживают перезагрузку хоста без дополнительных скриптов.\nVPS / выделенный сервер. Веб-приложения, приватные API, раннеры CI/CD - там, где нужен один надёжный хост без затрат на поддержку кластера.\nEdge / IoT. Минимальное потребление ресурсов, rootless-режим по умолчанию и простое сопровождение особенно ценны на слабом железе.\n6. Когда Quadlet - не то, что нужно # Если вам требуется:\nгоризонтальное автомасштабирование под нагрузкой;\nHA-кластер из нескольких физических узлов;\nmulti-region deployment с распределением нагрузки между дата-центрами,\nзначит, вы уже выросли из задач одного хоста, и здесь нужен полноценный Kubernetes. Quadlet отлично закрывает потребности single-node инфраструктуры, но сознательно не пытается конкурировать с оркестрацией на уровне кластера.\n7. Итог # Quadlet - декларативный формат, который превращает контейнеры, поды, сети и volume\u0026rsquo;ы Podman в обычные systemd-сервисы. Podlet - инструмент, который генерирует Quadlet-файлы из podman run, docker-compose.yml или уже работающих объектов, экономя время на ручном написании синтаксиса. Вместе они дают безопасную, минималистичную single-node платформу без демона и без Kubernetes - для большинства self-hosted сценариев этого более чем достаточно. Docker Compose - привычно, Podman - безопасно, Quadlet - декларативно и по-systemd\u0026rsquo;овски, Podlet - экономит время на переходе, Kubernetes - когда одного хоста уже мало. Выбор конкретного инструмента должен определяться реальной задачей, а не модой.\nПолезные ссылки:\nОфициальный сайт Podman Документация по Quadlet (man podman-systemd.unit) Репозиторий Podlet на GitHub ","date":"22 December 2025","externalUrl":null,"permalink":"/posts/quadelts-vs-podlets/","section":"Posts","summary":"Quadlet - декларативный формат systemd-юнитов для Podman, а Podlet - утилита, которая генерирует эти юниты из podman run и docker-compose.yml. Разбираем оба инструмента на практических примерах и сравниваем с Docker Compose.","title":"Quadlet и Podlet в Podman: как перестать писать длинные podman run и завести контейнеры под systemd","type":"posts"},{"content":" Введение # Homelabbing - это практика создания собственного домашнего лабораторного окружения для экспериментов с технологиями, сетями и серверами. По сути, это миниатюрная версия корпоративной ИТ-инфраструктуры, которую можно разворачивать и тестировать у себя дома. Homelab может включать в себя серверы, маршрутизаторы, коммутаторы, виртуальные машины, контейнеры и различные сервисы вроде облачных платформ или систем автоматизации.\nЗачем люди создают homelab # Цель homelabbing разнообразна и зависит от уровня опыта и интересов пользователя. Основные причины включают:\nОбучение и развитие навыков.\nHomelab позволяет безопасно изучать новые технологии без риска нарушить работу корпоративной сети. Это идеальная площадка для практики администрирования серверов, настройки сетевых протоколов, работы с базами данных, виртуализации и облачными сервисами.\nТестирование и эксперименты.\nЛюбой homelab предоставляет возможность экспериментировать с различным программным обеспечением и конфигурациями. Можно тестировать новые версии операционных систем, разворачивать собственные веб-сервисы, настраивать системы резервного копирования или автоматизации.\nSelf-hosting сервисов.\nМногие энтузиасты используют homelab для развёртывания собственных сервисов - например, облачного хранилища, медиа-серверов, VPN или систем умного дома. Это повышает независимость от внешних поставщиков и даёт полный контроль над данными.\nОптимизация и экономия.\nHomelab помогает изучить оптимизацию ресурсов, распределение нагрузки, балансировку серверов и контейнеров. Это полезно не только для личного опыта, но и для экономии ресурсов при развертывании собственных сервисов.\nКарьерный рост.\nДля специалистов в области ИТ и DevOps наличие собственного homelab может стать преимуществом при трудоустройстве. Он демонстрирует практический опыт работы с инфраструктурой, умение решать задачи и экспериментировать с современными технологиями.\nКомпоненты домашнего лабораторного окружения # Homelab может быть как простым, так и сложным. К базовым компонентам относятся:\nСерверное оборудование. Старые ПК, мини-серверы или специализированные устройства типа NUC. Сетевое оборудование. Роутеры, коммутаторы, точки доступа, виртуальные сети. Программное обеспечение. Виртуализация (Proxmox, VMware, VirtualBox), контейнеризация (Docker, Kubernetes), системы мониторинга и управления. Сервисы и приложения. Nextcloud, Plex, Home Assistant, базы данных, веб-серверы. Заключение # Homelabbing - это не только увлекательное хобби, но и мощный инструмент обучения и экспериментов. Он позволяет безопасно тестировать новые технологии, развивать навыки системного администрирования и сетевой инженерии, а также создавать собственные сервисы. Независимо от уровня подготовки, homelab предоставляет бесконечные возможности для практики, экспериментов и саморазвития в сфере ИТ. Для тех, кто хочет углубиться в мир технологий и получить практический опыт, создание собственного домашнего лабораторного окружения - это шаг к профессиональному росту и технической независимости.\n","date":"22 December 2025","externalUrl":null,"permalink":"/posts/homelabbing/","section":"Posts","summary":"Homelabbing - это создание домашней лаборатории для экспериментов с серверами, сетями и сервисами. Он помогает изучать технологии, тестировать новые решения и развивать практические навыки ИТ.","title":"Что такое homelabbing и зачем это нужно","type":"posts"},{"content":" How to Upgrade Linux-Based Server Distributions # Upgrading Debian, Ubuntu Server, and Fedora Server Versions # Upgrading the operating system is an important step for maintaining security, stability, and getting new features. In this article we\u0026rsquo;ll look at how to safely upgrade versions of popular server distributions: Debian, Ubuntu Server, and Fedora Server.\n1. Debian # Debian is known for its stability, but upgrading to a new version may require some preparation steps.\nUpgrade Procedure # Check the current version lsb_release -a or\ncat /etc/debian_version\nUpdate the current packages sudo apt update sudo apt upgrade -y sudo apt full-upgrade -y sudo apt autoremove -y Change the package sources Edit the /etc/apt/sources.list file, replacing the old release name with the new one:\n# Old: deb http://deb.debian.org/debian/bullseye main contrib non-free # New: deb http://deb.debian.org/debian/bookworm main contrib non-free Upgrade to the new version sudo apt update sudo apt upgrade -y sudo apt full-upgrade -y sudo reboot Check the version after the upgrade lsb_release -a 2. Ubuntu Server # Ubuntu Server is upgraded using do-release-upgrade.\nUpgrade Procedure # Check the current version lsb_release -a 2. Update all packages of the current version\nsudo apt update sudo apt upgrade -y sudo apt dist-upgrade -y sudo apt autoremove -y 3. Run the version upgrade\nsudo do-release-upgrade If the upgrade doesn\u0026rsquo;t start, make sure the update-manager-core package is installed:\nsudo apt install update-manager-core 4. Follow the upgrade wizard\u0026rsquo;s instructions\nUsually you\u0026rsquo;ll need to confirm replacing configuration files and a reboot.\n5. Check the version after the upgrade\nlsb_release -a 3. Fedora Server # Fedora Server uses the dnf tool to upgrade to a new version.\nUpgrade Procedure # Check the current version cat /etc/fedora-release Update the current system sudo dnf upgrade --refresh -y sudo dnf autoremove -y Install the version-upgrade plugin sudo dnf install dnf-plugin-system-upgrade -y Download the new version sudo dnf system-upgrade download --releasever=43 Replace 43 with your target Fedora version.\nApply the upgrade sudo dnf system-upgrade reboot Check the version after the upgrade cat /etc/fedora-release 4. Cheat Sheet: Upgrading Debian, Ubuntu Server, and Fedora Server # This table contains the main commands for safely upgrading Linux server distributions.\nDistribution Check Version Update Current Packages Upgrade OS Version Notes Debian lsb_release -a\ncat /etc/debian_version sudo apt update \u0026amp;\u0026amp; sudo apt upgrade -y \u0026amp;\u0026amp; sudo apt full-upgrade -y \u0026amp;\u0026amp; sudo apt autoremove -y 1. Change /etc/apt/sources.list to the new version\n2. sudo apt update \u0026amp;\u0026amp; sudo apt upgrade -y \u0026amp;\u0026amp; sudo apt full-upgrade -y \u0026amp;\u0026amp; sudo reboot Upgrading via apt requires carefully editing the package sources. Ubuntu Server lsb_release -a sudo apt update \u0026amp;\u0026amp; sudo apt upgrade -y \u0026amp;\u0026amp; sudo apt dist-upgrade -y \u0026amp;\u0026amp; sudo apt autoremove -y sudo do-release-upgrade Make sure update-manager-core is installed. Follow the wizard\u0026rsquo;s instructions. Fedora Server cat /etc/fedora-release sudo dnf upgrade --refresh -y \u0026amp;\u0026amp; sudo dnf autoremove -y 1. sudo dnf install dnf-plugin-system-upgrade -y 2. sudo dnf system-upgrade download --releasever=\u0026lt;target_version\u0026gt; 3. sudo dnf system-upgrade reboot Replace \u0026lt;target_version\u0026gt; with the desired Fedora version. 5. Upgrade Recommendations # Always back up important data before upgrading. Read the official guides and release notes for the version you\u0026rsquo;re upgrading to. On servers with critical services, it\u0026rsquo;s better to test the upgrade on a separate machine or virtual environment first. After upgrading, check the status of services and logs (systemctl status and journalctl). In summary, the upgrade process differs slightly between Debian/Ubuntu and Fedora, but the basic principle is the same - first update the current packages, then safely move to the new version using the built-in tools.\n","date":"December 12, 2025","externalUrl":null,"permalink":"/en/posts/update-linux-server/","section":"Posts","summary":"A detailed guide to safely upgrading Debian, Ubuntu Server, and Fedora Server distributions, with command examples","title":"How to Upgrade Linux Server Distributions","type":"posts"},{"content":"","date":"December 12, 2025","externalUrl":null,"permalink":"/en/categories/linux/","section":"Categories","summary":"","title":"Linux","type":"categories"},{"content":"","date":"December 12, 2025","externalUrl":null,"permalink":"/en/tags/linux/","section":"Tags","summary":"","title":"Linux","type":"tags"},{"content":"","date":"December 12, 2025","externalUrl":null,"permalink":"/en/tags/server/","section":"Tags","summary":"","title":"Server","type":"tags"},{"content":"Authentik is a modern, open-source identity and access management (IDP) system. It lets you centralize user authentication, connect third-party applications via SSO, OIDC, and SAML, and manage groups and access policies.\nIn this article, we\u0026rsquo;ll go over how to perform the initial setup of Authentik after installation - to quickly get your own IDP up and running.\nInitial registration # I\u0026rsquo;m assuming you\u0026rsquo;re using Docker for deployment. I provided a sample docker compose file in the previous article. Note that starting with version 2025.10.0, the developers removed the redis container from the equation. Unfortunately, the developers overlooked something in that version, and if you look at the postgres logs, you\u0026rsquo;ll see the postgres container giving us something like this\n2025-11-11 14:14:03.578 UTC WARNING: you don\u0026#39;t own a lock of type ExclusiveLock This should be fixed in future versions, but in any case, this bug doesn\u0026rsquo;t affect the application\u0026rsquo;s functionality in any way.\nSo, we\u0026rsquo;ve prepared our docker-compose file and started it with the good old docker compose up -d command\nCheck that all three containers are running. Since the application is far from lightweight, starting it up will take some time.\nOnce the application is running, we can navigate to the subdomain we assigned to the application via our reverse proxy, in my case that\u0026rsquo;s\nauthentik.stilicho.ru However, when we go to that address, the application asks us for a username and password, which we don\u0026rsquo;t have yet. The thing is, to create the initial administrator, you need to go to the link\nhttps://authentik.your_domain_name.ru/if/flow/initial-setup/ Note the trailing slash at the end of the link - that\u0026rsquo;s important\nNow you\u0026rsquo;ll land on the full initial registration menu\nEnter an email address and password, and it\u0026rsquo;s entirely unnecessary to use a real email - I\u0026rsquo;ll explain why a bit further down. Once you\u0026rsquo;ve entered all the required data, you land on the main menu. The home page, where all the applications we set up access to via Authentik will be displayed\nand the settings menu for Authentik itself\nCreating a new administrator # Now let me explain why I said not to bother with a real email for the administrator.\nThe thing is, by default, the first administrator we create has the nickname akadmin, and that\u0026rsquo;s a fixed value. So it\u0026rsquo;s much safer to create a new user, make them an administrator, and deactivate the original administrator.\nGo to Directory \u0026gt; Users \u0026gt; New User\nFill in all the necessary data. Be sure to specify an email address. Leave the attributes section alone for now. We\u0026rsquo;ll need it in the future, when we set up applications with OIDC, where users will be automatically created that are already present in Authentik, and we\u0026rsquo;ll need to assign the appropriate permissions to those users. In short, we\u0026rsquo;ll be managing user permissions for specific applications or services at the Authentik level.\nClick Create User\nNow we need to set a password. Of course, the password should be complex. I generate passwords using Vaultwarden, setting the length to at least 42 characters\nNow let\u0026rsquo;s grant our user superuser privileges.\nGo to Directory \u0026gt; Groups, and select the superadmin group authentik Admins\nGo to the Users tab, select Add existing user, click +, and add our new user. You\u0026rsquo;ll get a warning that \u0026ldquo;with great power comes great responsibility\u0026rdquo;, but we\u0026rsquo;re not afraid of anything.\nNow calmly log out of the akadmin account and log in as the new user.\nDisabling the default administrator # The next step is to disable the initial administrator account. Go to Directory \u0026gt; Users, click the down arrow next to our akadmin, and disable it with the deactivate button\nOverview of the admin/user settings panel # Clicking the ⚙ icon at the top next to our username takes us to the user\u0026rsquo;s personal settings menu\n👤 User profile # This section lets you view and change basic account details.\nAvailable fields:\nUsername - a unique username (unchangeable after creation). Display name - the name shown in the interface and when logging into applications. Email address - used for notifications, confirmation, and access recovery. Locale - the interface language. 🔒 Sessions # Shows all active sessions where the user is authenticated via Authentik.\nColumns:\nLast IP - the IP address the login was made from. Last used - the last time Authentik was accessed from this session. Expires - when the session expires. Available actions:\nTerminate an individual session (for example, if you logged out on a device). Terminate all sessions except the current one - for a full logout from all devices. 🔐 Useful if a device is lost or a password is changed.\n🪪 Consent # This section shows a list of applications the user has granted access to their data via OpenID Connect (OIDC).\nInformation for each entry:\nApplication name - the name of the application (e.g., Grafana, Vault, Gitea). Scopes - what data has been permitted for use (openid, email, profile, etc.). Date granted - when consent was given. Actions:\nRevoke consent - after this, the application loses access, and will ask for permission again on the next login. The most interesting menu section\n🔐 MFA Devices # Manage connected two-factor authentication devices.\nSupported types:\nTOTP - one-time codes (Google Authenticator, Authy, 1Password, etc.). WebAuthn / FIDO2 - hardware security keys (YubiKey, Touch ID, Windows Hello). Columns:\nDevice name - the name of the device. Last used - when it was last used. Added on - the date it was connected. Actions:\nAdd a new 2FA device. Remove a registered device. 💡 It\u0026rsquo;s recommended to have at least one backup device (for example, TOTP and WebAuthn).\n🔗 Connected services # Shows external services linked to the Authentik account.\nExample connections:\nGitHub Google Microsoft Entra ID (Azure AD) LDAP Columns:\nService - the name of the external provider. Last used - the last time this service was used to log in. Actions:\nDisconnect from the external provider (Unlink). 🔗 Allows logging in via external accounts without creating a new password.\n🧩 Tokens and App passwords # A section for managing personal access tokens and application passwords.\nUsed for:\nAccessing the Authentik API without an interactive login. Connecting CLI tools or integrations. Columns:\nName - the name of the token or application. Last IP - the IP the token was used from. Last used - the last time it was used. Expires - the expiration date. Actions:\nCreate a new token. Set an expiration date and access level (scopes). Delete or revoke an existing token. 🔒 A created token is shown only once - save it somewhere safe.\n🧭 Summary # The User Settings section in Authentik lets a user:\nView and edit their profile data, Control active sessions, Manage granted permissions (Consent), Connect or remove 2FA devices, Configure external login services, Create and revoke API tokens. This is a powerful self-service tool that simplifies security and personal data management.\n","date":"November 16, 2025","externalUrl":null,"permalink":"/en/posts/authentik-setup/","section":"Posts","summary":"A detailed overview of the initial setup of Authentik - an open source system for centralized authentication and authorization (IdP/SSO). We’ll walk through the very first steps of setting up Authentik.","title":"Authentik: initial setup after installation","type":"posts"},{"content":" OIDC, OAuth2, and Proxy Provider in Authentik - how to protect any application # In this article, I\u0026rsquo;ll try to describe how to set up authorization in applications using OIDC technology or Authentik\u0026rsquo;s built-in proxy provider.\nA bit of theory first.\nWhat is OIDC # OIDC (OpenID Connect) is a modern authorization and authentication protocol built on top of OAuth 2.0. While OAuth2 on its own solves the problem of granting access rights (authorization), OIDC adds confirmation of the user\u0026rsquo;s identity (authentication).\nPut simply:\nOIDC = \u0026ldquo;who the user is\u0026rdquo; + \u0026ldquo;can they be granted access\u0026rdquo;, built on OAuth2.\nHow it works # The user tries to log in to an application. The application sends them to the authorization server (Identity Provider) with a request essentially saying \u0026ldquo;I want to find out who this is\u0026rdquo;. The user logs in with the provider. The provider returns: an ID Token - a JWT token with information about the user (name, email, ID, etc.). an Access Token - an access token (as in OAuth2). The application receives confirmed information about the user and lets them in. Key concepts # ID Token # The main \u0026ldquo;feature\u0026rdquo; of OIDC - it contains data about the user:\nsub - a unique identifier name email issuance time, expiration time, etc. OpenID Provider (OP) # The server that logs users in and issues tokens:\nKeycloak, Authentik, Authelia, Zitadel, Google, GitHub, etc.\nRelying Party (RP) # The application that trusts the provider and accepts its tokens.\nWhy OIDC is needed # Centralized authentication (one login for many services). Better interoperability between different systems. Single Sign-On (SSO) capability. Easy integration with applications (via standard libraries). Where it\u0026rsquo;s used # Practically everywhere:\nKeycloak Authentik Authelia Zitadel Google Sign-In GitHub Login Kubernetes (via Dex) Traefik / Nginx / Envoy as an OIDC proxy What is OAuth 2.0 # OAuth 2.0 is an authorization protocol that allows one service to gain limited access to a user\u0026rsquo;s resources on another service without transmitting the password.\nPut simply:\nOAuth 2.0 is a way to grant an application access \u0026ldquo;on behalf of the user\u0026rdquo; without revealing the login and password.\nWhy OAuth2 is needed # Common scenarios:\nYou want to log in to a service via Google / GitHub / VK / Facebook. An application wants access to, say, only your photos, but not your email. Microservices want to securely \u0026ldquo;talk\u0026rdquo; to each other. How it works (a very simple diagram) # The application wants to do something on behalf of the user → sends a request to the Authorization Server. The user logs in on that server. The server returns an Authorization Code. The application exchanges the code for an Access Token. The application uses the Access Token to access the API. The user\u0026rsquo;s password remains known only to the authorization server.\nKey OAuth2 entities # Authorization Server # Issues tokens (for example: Authentik, Keycloak, Authelia, Google).\nResource Server # The API or service that needs to be accessed (files, mail, profile, etc.).\nClient # The application that needs access.\nAccess Token # The token the client uses to access resources.\nRefresh Token # Allows obtaining a new Access Token without logging in again.\nGrants (authorization types) # The most commonly used is the Authorization Code Flow, especially with PKCE for secure SPAs and mobile apps.\nOthers:\nClient Credentials - service-to-service authorization Refresh Token - refreshing tokens Device Code Flow - devices without a keyboard (TV, set-top boxes) Password Grant - deprecated, NOT used Key takeaway # OAuth 2.0 does not confirm the user\u0026rsquo;s identity (who they are).\nIt only grants permissions (what they can do).\nOIDC is used to confirm identity - it\u0026rsquo;s a layer on top of OAuth2.\nWhat\u0026rsquo;s the difference between OIDC and OAuth 2.0 # The short version # OAuth2 is about access (\u0026ldquo;let the application do something on my behalf\u0026rdquo;). OIDC is about identity (\u0026ldquo;who is this user?\u0026rdquo;), built on top of OAuth2. A real-life analogy # OAuth2 - power of attorney # You give a courier a power of attorney to pick up your package.\nThe courier doesn\u0026rsquo;t know who you are. They just received permission to perform an action.\nOIDC - a passport + power of attorney # Now you\u0026rsquo;ve also shown your passport, and the service knows exactly who got access.\nKey difference # What we\u0026rsquo;re comparing OAuth 2.0 OIDC What it does Grants access Confirms identity Protocol type Authorization Authentication + authorization Which tokens Access Token Access Token + ID Token What the client can learn Whether or not an action can be performed Who the user is (email, name, ID) Where it\u0026rsquo;s used API access Logging into applications Why OIDC came about # OAuth2 doesn\u0026rsquo;t say who the user is.\nThe application gets access, but doesn\u0026rsquo;t get profile data and doesn\u0026rsquo;t know who\u0026rsquo;s logged in.\nTo solve this problem, they created:\nOIDC = OAuth2 + ID Token + UserInfo API + SSO standards.\nUsage examples # OAuth2 # Grant an application access to the YouTube API A \u0026ldquo;Google Drive file access\u0026rdquo; scenario Microservice-to-microservice communication OIDC # Logging in via Google / GitHub Company-wide SSO Authorization in Keycloak/Authentik/Authelia/Zitadel Summary (brief) # OAuth2 says what can be done. OIDC says who is doing it. Proxy Provider in Authentik # Proxy Provider in Authentik is a special type of provider that lets Authentik act as a transparent \u0026ldquo;proxy layer\u0026rdquo; between the user and an external service, adding authentication and access control where the service itself doesn\u0026rsquo;t support it.\nPut simply:\nProxy Provider is a way to protect any web service, even if it doesn\u0026rsquo;t support OAuth2 / OIDC / SAML at all.\nAuthentik \u0026ldquo;inserts itself\u0026rdquo; between the user and the application as a reverse proxy.\nHow it works # The user tries to open the application. The request doesn\u0026rsquo;t go directly to the application, but to the Authentik Proxy Provider, which works through nginx/traefik/caddy or is embedded as a sidecar. Authentik: checks whether the user is logged in; if not - sends them to the login page; after login, forwards the request on to the application. The application receives headers containing information about the user, for example: X-authentik-username X-authentik-email X-authentik-groups The application accepts this data as fact - it doesn\u0026rsquo;t understand OIDC, but it can read headers.\nWhen you need a Proxy Provider # When a service doesn\u0026rsquo;t have: # OIDC OAuth2 SAML LDAP When you need to protect: # Legacy web applications Admin panels (Grafana without SSO, Adminer, phpMyAdmin) Web UIs of Docker containers Home services on the local network APIs that can\u0026rsquo;t be modified What the Proxy Provider gives you # Authorization via Authentik (password, 2FA, OTP, WebAuthn). Access restriction by group / role. Passing user attributes via headers. Unified SSO for old applications. The ability to combine it with reverse proxies: Traefik Nginx Caddy Example: how it works with Traefik # Traefik redirects requests to the Authentik Proxy Provider → Authentik checks the user → returns them to Traefik → which forwards the request to the application along with headers containing the user\u0026rsquo;s information.\nFlow diagram (Proxy Provider → Authentik → application) # sequenceDiagram participant U as User participant P as Proxy (Traefik / Nginx / Caddy) participant A as Authentik participant S as Service / Application U-\u0026gt;\u0026gt;P: 1. Opens the application URL P-\u0026gt;\u0026gt;U: Checks session\u0026lt;br/\u0026gt;If absent - redirect P-\u0026gt;\u0026gt;A: 2. Redirects to the login page A-\u0026gt;\u0026gt;U: 3. Login form (password, 2FA, WebAuthn) U-\u0026gt;\u0026gt;A: Enters credentials A-\u0026gt;\u0026gt;P: 4. Successful authentication\u0026lt;br/\u0026gt;Redirect back to the proxy P-\u0026gt;\u0026gt;S: 5. Forwards headers\u0026lt;br/\u0026gt;with user data S-\u0026gt;\u0026gt;U: 6. Access to the protected application Step-by-step explanation, even shorter # The user → visits the service Traefik/Nginx → redirects to Authentik Authentik → asks for login / 2FA Authentik → gives the proxy a \u0026ldquo;mark\u0026rdquo; that the user is authenticated The proxy → adds headers with the user\u0026rsquo;s data The application → accepts the headers → the user is in Summary # Proxy Provider is a way to add SSO + protection + access control to any application, even if it doesn\u0026rsquo;t support that itself.\nIn the next article, we\u0026rsquo;ll move on from boring theory to more interesting practice.\n","date":"November 16, 2025","externalUrl":null,"permalink":"/en/posts/authentik-overview-proxy-oidc/","section":"Posts","summary":"A detailed explanation of how Authentik’s Proxy Provider adds authentication and SSO to any application. A simple flow diagram, key concepts, and usage examples.","title":"OIDC, OAuth2, and Proxy Provider in Authentik - how to protect any application","type":"posts"},{"content":" History of OPNsense # Origins and motivation # The roots of OPNsense trace back to the m0n0wall project - a lightweight FreeBSD-based distribution designed for embedded systems and network gateways. It emerged back in the early 2000s and for years became the standard for anyone who needed a firewall running on decommissioned hardware without licensing headaches. Later, pfSense emerged from m0n0wall, which took over most of the audience and became, for a long time, the most popular platform for FreeBSD-based firewalls and routers. It was pfSense that many homelab enthusiasts encountered as \u0026ldquo;the only option\u0026rdquo; for a router OS as far back as ten years ago.\nBy the mid-2010s, part of the community and the developers behind pfSense began to diverge in their views on what the project\u0026rsquo;s future should look like. It wasn\u0026rsquo;t about one particular complaint, but a whole set of issues at once:\na more open development model, rather than decisions made behind closed doors by a single company; a transparent licensing scheme without the risk that some functionality would suddenly move behind a paywall; modern, secure code - at the time, pfSense\u0026rsquo;s codebase seemed outdated to many; a clear and predictable release structure. In 2014, the Dutch company Deciso B.V. announced the creation of a new project - OPNsense, a fork of pfSense on FreeBSD, licensed under the BSD 2-Clause License, which allows free use, modification, and sale of the code, including commercial use, as long as attribution is retained (which is what OnlyOffice should have chosen from the start).\nProject launch # Founding date: January 2, 2015 First release: OPNsense 15.1 Ascending Albatross (January 5, 2015) Main project goals: Security and code quality Regular updates An active community A modern and clear web interface Stages of development # The project grew quickly, establishing a clear release cycle:\ntwo major releases per year - in January and July; security updates every two weeks. Key development milestones include moving to new FreeBSD versions, adopting HardenedBSD, an interface and API overhaul, and security improvements.\nOPNsense release timeline # Version Codename Date Key highlights 15.1 Ascending Albatross Jan 2015 The project\u0026rsquo;s first release 15.7 Brave Badger Jul 2015 Transition to a mature version 16.1 Crafty Coyote Jan 2016 Stability improvements 16.7 Dancing Dolphin Jul 2016 New networking features, UEFI support 17.1 Eclectic Eagle Jan 2017 Plugin support, PHP updates 17.7 Free Fox Jul 2017 Move to HardenedBSD, enhanced security 18.1 Groovy Gecko Jan 2018 Hardening of the kernel and security architecture 19.1 Inspiring Iguana Jan 2019 Alias API, HardenedBSD 11.2 19.7 Jazzy Jaguar Jul 2019 Updated interface, expanded logging 20.1 Keen Kingfisher Jan 2020 Last version with i386 support, improved GUI 20.7 Legendary Lion Jul 2020 HardenedBSD 12.1, Suricata 5, amd64-only 21.1 Marvelous Meerkat Jan 2021 UI improvements, updated firewall rules 21.7 Noble Nightingale Jul 2021 ZFS support, PHP 7.4 → Python 3.8 22.1 Observant Owl Jan 2022 Move to FreeBSD 13, IPv6 alias, RFC 5424 logging 22.7 Powerful Panther Jul 2022 FreeBSD 13.1, PHP 8.0, basic DDoS features 23.1 Quintessential Quail Jan 2023 PHP 8.1, WireGuard improvements, new API 23.7 Restless Roadrunner Jul 2023 OpenVPN improvements, PHP 8.2 24.1 Savvy Shark Jan 2024 Interface and performance improvements 24.7 Thriving Tiger Jul 2024 FreeBSD 14.1, Python 3.11, new Dashboard 25.1 Ultimate Unicorn Jan 2025 10th anniversary, FreeBSD 14.2, PHP 8.3, ZFS snapshot 25.7 Visionary Viper Jul 2025 FreeBSD 14.3, improved GUI, Alias acceleration 26.1 Witty Woodpecker Jan 2026 Dnsmasq as the default for DHCP, ISC DHCP - plugin only, Suricata 8, Firewall Rules redesign 26.7 Xenial Xenops Jul 2026 FreeBSD 15.1, OpenVPN 2.7, PHP 8.5, Python 3.13, Outbound NAT migration to Source NAT Legal and organizational aspects # In 2017, Netgate (the creators of pfSense) lost a dispute over the opnsense.com domain. WIPO (case D2017-1828) ruled that the domain should be transferred to Deciso. This cemented the legal independence of the OPNsense brand. The fact is, the legal dispute mentioned above was preceded by a rather unflattering episode. Netgate had managed to register the opnsense.com domain even before the project officially launched, and used it not as a neutral placeholder, but to publish critical material about the new fork - which many in the community saw not so much as an attempt to protect their own reputation, but as an attempt to slow down a competitor right out of the gate. The community did not look kindly on this behavior, and WIPO ultimately sided with OPNsense.\nProject characteristics # Over more than ten years, OPNsense has developed a set of traits that set it apart not only from pfSense, but from most open-source router distributions in general.\nSecurity is baked into the process here: security updates come out every two weeks rather than \u0026ldquo;whenever we absolutely have to,\u0026rdquo; and the system\u0026rsquo;s kernel has for years run on HardenedBSD - a fork of FreeBSD with additional memory protection mechanisms and address-space randomization. Modularity is implemented through a plugin system and an open API - you can bolt on functionality (WireGuard, IDS/IPS, proxy, 2FA) without having to patch the system by hand. Openness shows not only in the license, but in the fact that the project\u0026rsquo;s roadmap is public, and community proposals actually make it into releases rather than sitting in some backlog. And finally, the BSD-2-Clause license - Deciso does have a paid Business Edition, but it\u0026rsquo;s not a \u0026ldquo;crippled free version\u0026rdquo; with locked-away features, as is often the case with competitors: the difference is only a more conservative update pace and access to some commercial plugins (for example, Zenarmor, though it\u0026rsquo;s also available in the free version) and support. The entire core firewall functionality is equally available in the community version.\nCurrent state (2026) # Based on FreeBSD 15.1 Actively maintained by Deciso B.V. A community of thousands of participants worldwide Has a large number of ready-made plugins and integrations (WireGuard, Zenarmor, CrowdSec, and others) Significance for the community # Over more than ten years, OPNsense has stopped being just \u0026ldquo;a pfSense fork for people annoyed at Netgate\u0026rdquo; and has become an independent project with its own audience, its own release cadence, and its own development philosophy. What started as an alternative is, for many, today a conscious first choice rather than a fallback option. What\u0026rsquo;s more, a bit over two years ago, a mass exodus from PfSense began after they changed their software distribution terms.\nPersonally, what I find most interesting in this story isn\u0026rsquo;t the domain dispute itself (the behavior of Netgate\u0026rsquo;s head has long been a byword), but the fact that over the years the project has genuinely kept its pace: a release every six months, security patches every two weeks, and no drift toward \u0026ldquo;let\u0026rsquo;s simplify things and put the complex stuff behind a paywall.\u0026rdquo; That\u0026rsquo;s exactly why, in my own Proxmox homelab, I ultimately settled on OPNsense as my main gateway - not because pfSense is bad in some way, but because I can see where each of these projects is heading, and I like the direction OPNsense is going.\nUseful links # Official website Documentation Plugin list Deciso B.V. Historical article on PRWeb - 10 years of OPNsense ","date":"November 5, 2025","externalUrl":null,"permalink":"/en/posts/opnsense-history/","section":"Posts","summary":"The history of the creation and development of OPNsense - a branch of the pfSense project that became an independent and actively developed open-source solution. We look at the reasons for the fork, the philosophy of the project, key stages of development, and how OPNsense differs from other open-source routers.","title":"History of OPNsense - from m0n0wall to a modern firewall","type":"posts"},{"content":"","date":"November 5, 2025","externalUrl":null,"permalink":"/en/categories/opnsense/","section":"Categories","summary":"","title":"OPNsense","type":"categories"},{"content":"A series of articles about setting up and using OPNsense - a powerful and flexible open-source router.\nWe cover installation, network interface configuration, DNS over TLS, Kea DHCP, VPN, Firewall, and other features useful for home and corporate network environments.\n","date":"November 5, 2025","externalUrl":null,"permalink":"/en/posts/opnsense/","section":"Posts","summary":"A series of articles about setting up and using OPNsense - a powerful and flexible open-source router. We cover installation, network interface configuration, DNS over TLS, Kea DHCP, VPN, Firewall, and other features useful for home and corporate network environments","title":"OPNsense","type":"posts"},{"content":"","date":"November 5, 2025","externalUrl":null,"permalink":"/en/tags/opnsense/","section":"Tags","summary":"","title":"OPNsense","type":"tags"},{"content":"","date":"November 5, 2025","externalUrl":null,"permalink":"/en/tags/pfsense/","section":"Tags","summary":"","title":"PfSense","type":"tags"},{"content":"","date":"November 5, 2025","externalUrl":null,"permalink":"/en/series/working-with-opnsense/","section":"Series","summary":"","title":"Working With Opnsense","type":"series"},{"content":"","date":"November 4, 2025","externalUrl":null,"permalink":"/en/tags/adguard/","section":"Tags","summary":"","title":"AdGuard","type":"tags"},{"content":"A series of articles on networking technologies and tools, from the basic principles of routing and VLANs to configuring VPN, DHCP, DNS, and firewalls. Detailed practical guides for working with OPNsense, Proxmox, Traefik, and other systems for building home and corporate networks.\n","date":"November 4, 2025","externalUrl":null,"permalink":"/en/posts/network/","section":"Posts","summary":"A series of articles on networking technologies and tools, from the basic principles of routing and VLANs to configuring VPN, DHCP, DNS, and firewalls. Detailed practical guides for working with OPNsense, Proxmox, Traefik, and other systems for building home and corporate networks.","title":"Network","type":"posts"},{"content":"","date":"November 4, 2025","externalUrl":null,"permalink":"/en/series/network/","section":"Series","summary":"","title":"Network","type":"series"},{"content":"","date":"November 4, 2025","externalUrl":null,"permalink":"/en/categories/networking-technologies/","section":"Categories","summary":"","title":"Networking Technologies","type":"categories"},{"content":"","date":"November 4, 2025","externalUrl":null,"permalink":"/en/tags/pi-hole/","section":"Tags","summary":"","title":"Pi-Hole","type":"tags"},{"content":" Split DNS - LinuxServer.io # What Split DNS is, in brief # The term Split DNS is usually translated into Russian as \u0026ldquo;split DNS\u0026rdquo; or \u0026ldquo;split domain name system.\u0026rdquo;\nThe idea behind the concept is this: the same domain (for example, stilicho.ru) resolves differently depending on which network the client is querying from: internal (LAN) or external (the internet).\nTranslation and usage examples:\nSplit DNS → Split DNS Split-horizon DNS → sometimes also called Split DNS or DNS with a split horizon What Split DNS is, in more detail # Below is a translation of the article from LinuxServer.io\nSplit DNS lets you give different answers to DNS queries for internal and external users, so local requests to your server don\u0026rsquo;t have to go through the router. This has several advantages:\nFaster, since there\u0026rsquo;s no need to go through the router. A reverse proxy can easily distinguish between internal and external requests, allowing/denying them, since there\u0026rsquo;s no NAT involved. Everything keeps working even without internet access. The system keeps working even if the upstream DNS server (your ISP/Google/OpenDNS, etc.) is unavailable. Requirements # An internal reverse proxy listening on port 80/443. An internal DNS resolver that supports overrides or hosting full DNS zones. Popular DNS configurations # In these examples, domain.com is assumed to be your domain and 10.10.10.10 your reverse proxy.\nOPNsense # Go to Services \u0026gt; Unbound DNS \u0026gt; Overrides \u0026gt; Host Overrides \u0026gt; Add:\nHost: * Domain: domain.com Type: A or AAAA IP: 10.10.10.10 pfSense # Go to Services \u0026gt; DNS Resolver \u0026gt; General Setting \u0026gt; Host Overrides \u0026gt; \u0026ldquo;Add.\u0026rdquo;\nHost: * Domain: domain.com IP Address: 10.10.10.10 Pi-hole and dnsmasq # Enable dnsmasq.d on pihole (only needed for version 6 or higher; the video was recorded on version 5) with the following command:\nsudo pihole-FTL --config misc.etc_dnsmasq_d true Create a file /etc/dnsmasq.d/domain.conf with the following content:\naddress=/domain.com/10.10.10.10 AdGuard Home # Go to Filters \u0026gt; DNS rewrites \u0026gt; Add DNS rewrite:\nDomain name: *.domain.com IP Address: 10.10.10.10 Problems with Wireguard # When granting access to a Wireguard server, the Wireguard subdomain should not be split, otherwise the connection will drop when switching between Wi-Fi and mobile data.\nFor example, you can exclude wg.domain.com in AdguardHome by creating another DNS rewrite - from wg.domain.com to wg.domain.com, which excludes it from the split.\nNAT Reflection / NAT Loopback / Hairpin NAT # NAT Reflection is an alternative to split DNS that can provide some, but not all, of the benefits of split DNS. It lets local network devices use the external IP address and get port forwarding without NAT.\nThis is usually a setting on specific routers that can be enabled with the corresponding flag.\nNote that using the Cloudflare proxy (that\u0026rsquo;s the orange cloud, which is currently being blocked by Roskomnadzor) will bypass this and still send traffic out.\n","date":"November 4, 2025","externalUrl":null,"permalink":"/en/posts/split-dns/","section":"Posts","summary":"Split DNS - configuring domain names with different resolution for the internal network and the internet. Operating principles, advantages, and usage examples.","title":"Split DNS - a guide from LinuxServer.io","type":"posts"},{"content":"","date":"4 November 2025","externalUrl":null,"permalink":"/categories/%D1%81%D0%B5%D1%82%D0%B5%D0%B2%D1%8B%D0%B5-%D1%82%D0%B5%D1%85%D0%BD%D0%BE%D0%BB%D0%BE%D0%B3%D0%B8%D0%B8/","section":"Categories","summary":"","title":"Сетевые Технологии","type":"categories"},{"content":"","date":"November 1, 2025","externalUrl":null,"permalink":"/en/tags/diun/","section":"Tags","summary":"","title":"Diun","type":"tags"},{"content":" Diun - notifications about Docker image updates # What is Diun # Diun (Docker Image Update Notifier) is an open-source tool developed by CrazyMax that watches for Docker image updates and notifies you when a new version comes out.\nDiun doesn\u0026rsquo;t update containers automatically - it only tells you that a new version of an image is available, leaving the decision up to you. This is especially important if you want to control the update process and avoid unexpected changes in production.\nThis is a significant difference from an app like Watchtower, which not only checks for a new version but also installs it right away.\nDIUN is the recommended container monitoring app according to linuxserver.io\nWhy you need Diun # If you have a home server, a Proxmox cluster, or just a few containers on a VPS, images become outdated over time. Checking for updates manually is inconvenient.\nDiun solves this automatically:\nChecks Docker Hub, GHCR, Quay.io, GitLab, and private registries Runs on a cron schedule or at startup Sends notifications through dozens of services Supports filters and tags Can track containers, compose files, stacks, or registry lists Installing Diun via Docker Compose # Create a directory and a docker-compose.yml file.\nBelow is the docker compose file I used in the video.\nservices: diun: # Определяем сервис Diun в составе Docker Compose image: crazymax/diun:latest # Официальный образ Diun с Docker Hub container_name: diun # Имя контейнера (для удобства в `docker ps`) command: serve # Основная команда - запустить веб/cron-сервис Diun volumes: - \u0026#34;/path/to/user/directory/data:/data\u0026#34; # Локальный каталог для хранения базы данных и конфигурации Diun - \u0026#34;/var/run/docker.sock:/var/run/docker.sock\u0026#34; # Доступ к Docker API для отслеживания образов и контейнеров environment: - \u0026#34;TZ=Europe/Moscow\u0026#34; # Устанавливаем часовой пояс (важно для cron и временных меток) - \u0026#34;LOG_LEVEL=info\u0026#34; # Уровень логирования: trace | debug | info | warn | error | fatal | panic - \u0026#34;DIUN_WATCH_WORKERS=50\u0026#34; # Количество параллельных потоков при проверке образов (ускоряет работу при множестве контейнеров) - \u0026#34;DIUN_WATCH_SCHEDULE=0 */6 * * *\u0026#34; # Cron-расписание: проверять обновления каждые 6 часов - \u0026#34;DIUN_WATCH_JITTER=30s\u0026#34; # Добавляет случайную задержку (до 30 секунд), чтобы избежать одновременного старта нескольких задач - \u0026#34;DIUN_WATCH_RUNONSTARTUP=true\u0026#34; # Запуск проверки сразу при старте контейнера, не дожидаясь расписания - \u0026#34;DIUN_PROVIDERS_DOCKER=true\u0026#34; # Активирует провайдер Docker: Diun будет отслеживать образы запущенных контейнеров - \u0026#34;DIUN_PROVIDERS_DOCKER_WATCHBYDEFAULT=true\u0026#34; # Включает мониторинг всех контейнеров по умолчанию, без необходимости вручную задавать label `diun.enable=true` # --- Настройки уведомлений через Telegram --- - \u0026#34;DIUN_NOTIF_TELEGRAM_TOKEN=token\u0026#34; # Токен Telegram-бота, созданного через @BotFather - \u0026#34;DIUN_NOTIF_TELEGRAM_CHATIDS=chatid\u0026#34; # ID чата или пользователя, куда будут отправляться уведомления (можно указать несколько через запятую) # --- Настройки уведомлений через Gotify --- - \u0026#34;DIUN_NOTIF_GOTIFY_ENDPOINT=https://gotify.domain.ru\u0026#34; # URL вашего сервера Gotify - \u0026#34;DIUN_NOTIF_GOTIFY_TOKEN=token\u0026#34; # Токен приложения Gotify (создаётся в веб-интерфейсе Gotify) - \u0026#34;DIUN_NOTIF_GOTIFY_PRIORITY=1\u0026#34; # Приоритет уведомления (0 - низкий, 5 - высокий) - \u0026#34;DIUN_NOTIF_GOTIFY_TIMEOUT=10s\u0026#34; # Таймаут ожидания ответа от Gotify при отправке уведомления labels: - \u0026#34;diun.enable=true\u0026#34; # Метка, разрешающая Diun отслеживать этот контейнер (опционально, если `WATCHBYDEFAULT=false`) restart: always # Перезапуск контейнера при сбое или перезагрузке Docker-хоста After the first launch, Diun will create the data/diun.db database and start monitoring all Docker containers. You can see more details in the app\u0026rsquo;s logs.\nDiun is highly configurable. Below is a brief overview of the most useful features.\nOperating modes # Watch - Diun periodically scans all containers to check for updates. Events - reacts to a container starting and checks whether a newer image is available. Database mode - stores the state of all checked images so it doesn\u0026rsquo;t send duplicate notifications. Container labels # You can specify which containers to track. Add this to docker-compose.yml:\nlabels: - \u0026#34;diun.enable=true\u0026#34; or, conversely, exclude containers you don\u0026rsquo;t need.\nProviders # Diun supports different sources:\ndocker - works with the local Docker daemon swarm - tracks images in Docker Swarm file - a list of images in a YAML file kubernetes - (experimental) checks images in pods watchtower - imports configuration from Watchtower Example of a YAML provider:\ndb: path: diun.db watch: workers: 20 schedule: \u0026#34;0 */6 * * *\u0026#34; regopts: - name: \u0026#34;myregistry\u0026#34; username: fii password: bor timeout: 5s - name: \u0026#34;docker.io/crazymax\u0026#34; selector: image username: fii password: bor - name: \u0026#34;docker.io\u0026#34; selector: image username: foo password: bar providers: file: filename: /path/to/config.yml ### /path/to/config.yml # Watch latest tag of crazymax/nextcloud image on docker.io (DockerHub) # with registry options named \u0026#39;docker.io/crazymax\u0026#39; (image selector). - name: docker.io/crazymax/nextcloud:latest # Watch 4.0.0 tag of jfrog/artifactory-oss image on frog-docker-reg2.bintray.io (Bintray) # with registry options named \u0026#39;myregistry\u0026#39; (name selector). - name: jfrog-docker-reg2.bintray.io/jfrog/artifactory-oss:4.0.0 regopt: myregistry # Watch coreos/hyperkube image on quay.io (Quay) and assume latest tag. # Add foo=bar metadata to be used in notification template. - name: quay.io/coreos/hyperkube metadata: foo: bar # Watch crazymax/swarm-cronjob image and assume docker.io registry and latest tag # with registry options named \u0026#39;docker.io/crazymax\u0026#39; (image selector). # Only include tags matching regexp ^1\\.2\\..* and only be notified on new tag. - name: crazymax/swarm-cronjob watch_repo: true notify_on: - new include_tags: - ^1\\.2\\..* # Watch portainer/portainer image on docker.io (DockerHub) and assume latest tag # with registry options named \u0026#39;docker.io\u0026#39; (image selector). # Only watch latest 10 tags and include tags matching regexp ^\\d+\\.\\d+\\..* - name: docker.io/portainer/portainer watch_repo: true max_tags: 10 include_tags: - ^\\d+\\.\\d+\\..* # Watch alpine image (library) and assume docker.io registry and latest tag # with registry options named \u0026#39;docker.io\u0026#39; (image selector). # Force linux/arm64/v8 platform for this image - name: alpine watch_repo: true platform: os: linux arch: arm64 variant: v8 You can read more in the official documentation\nNotifications # Diun can send notifications to more than 15 services:\nService Environment variables Telegram DIUN_NOTIF_TELEGRAM_TOKEN, DIUN_NOTIF_TELEGRAM_CHATIDS Discord DIUN_NOTIF_DISCORD_WEBHOOKURL Gotify DIUN_NOTIF_GOTIFY_ENDPOINT, DIUN_NOTIF_GOTIFY_TOKEN Slack DIUN_NOTIF_SLACK_WEBHOOKURL Email DIUN_NOTIF_MAIL_SMTP_HOST, DIUN_NOTIF_MAIL_FROM, DIUN_NOTIF_MAIL_TO Webhook DIUN_NOTIF_WEBHOOK_ENDPOINT You can use several notification services at once, as I did in my docker compose file.\nConclusion # Diun is a must-have tool for anyone running Docker in a self-hosted infrastructure.\nIt\u0026rsquo;s lightweight, stable, requires no complex setup, and pairs nicely with other DevOps services.\nIf you want to keep your infrastructure up to date, Diun will help you learn about updates in time and avoid surprises.\n","date":"November 1, 2025","externalUrl":null,"permalink":"/en/posts/diun-docker-update-notifications/","section":"Posts","summary":"A detailed guide to installing and configuring Diun for tracking Docker image updates. Covers deployment steps, integration with notification services, and monitoring automation, so you can update your containers on time and improve system security.","title":"Diun - notifications about Docker image updates","type":"posts"},{"content":"","date":"November 1, 2025","externalUrl":null,"permalink":"/en/categories/docker/","section":"Categories","summary":"","title":"Docker","type":"categories"},{"content":"","date":"October 31, 2025","externalUrl":null,"permalink":"/en/tags/obsidian/","section":"Tags","summary":"","title":"Obsidian","type":"tags"},{"content":" Obsidian vs TriliumNext - a comparison of knowledge management systems # Organizing personal knowledge, notes, and ideas is becoming an increasingly important task - whether you\u0026rsquo;re a developer, a researcher, or just an ordinary person like me who wants to bring order to the information that piles up on us every day.\nToday we\u0026rsquo;re comparing Obsidian and TriliumNext - two popular solutions for personal knowledge management (PKM).\nNote Update. At the time this article was written, the community fork lived under the name TriliumNext. In 2025 the project got the original repository and name back from the author of the original Trilium - it\u0026rsquo;s now simply Trilium again, not a fork. Below I keep the name TriliumNext as it was at the time of the comparison, but in fact this refers to the current Trilium. More details in a separate article about installing Trilium.\nWhat is Obsidian # Obsidian is a desktop app for note-taking and knowledge management based on Markdown files.\nEach note is a plain .md file stored locally, and links between notes form a network of ideas.\nMain features: # Works on Windows, macOS, Linux, Android, and iOS Stores data locally, with no cloud dependency Uses links between notes and a graph visualization Supports plugins, themes, and interface customization Has paid services - Obsidian Sync and Obsidian Publish Advantages: # Simple data storage in an open Markdown format A huge plugin ecosystem Great fit for the \u0026ldquo;second brain\u0026rdquo; concept (well, since we\u0026rsquo;ve sorted out the first one) Flexible knowledge organization (tags, links, graph view) Drawbacks: # Some features (sync, publishing) are paid Can be complex for beginners due to the sheer number of settings Dependency on plugins (risk of incompatibility on updates) It can\u0026rsquo;t really be called an open-source solution No official Docker image (I used the one from LinuxServer) What is TriliumNext # TriliumNext is an actively developed fork of Trilium Notes, focused on hierarchical knowledge organization.\nUnlike Obsidian, it uses a database and a tree (not really a fully tree-like structure, but for lack of a better term, let\u0026rsquo;s call it a tree) of notes instead of separate files.\nMain features: # Fully open-source, supports self-hosting Web interface + desktop app (clients for all three OSes exist) Deep hierarchical structure of notes (a tree) Support for attributes, templates, versions, and cloning (which is why it\u0026rsquo;s not quite a tree) Sync between devices out of the box and for free (Obsidian? Never heard of it) Advantages: # Powerful and flexible knowledge base structure Lots of built-in features - diagrams, code blocks, formulas Can be hosted on your own server (Docker, NAS) Suited to advanced scenarios, corporate wikis, and knowledge bases Drawbacks: # The learning curve may feel steeper to some The interface is less friendly than Obsidian\u0026rsquo;s (though that\u0026rsquo;s subjective). For anyone used to MS Word, it will feel easy to get into. No official mobile app. The interface is adapted for use on mobile devices. Comparison by key parameters # Parameter Obsidian TriliumNext Storage format Local Markdown files Built-in database Knowledge organization Network of notes and graph view Tree hierarchy with attributes Ease of getting started High - simple to start Requires setup and understanding the structure Extensibility Community plugins and themes Many built-in features Sync Via Obsidian Sync (paid) or Git Via a built-in server or WebDAV Mobile apps Full-featured iOS/Android clients Browser or experimental app Self-Hosting Not required Recommended for full control Best suited for Individual notes and ideas, knowledge base Knowledge bases, documentation, corporate wikis (though some solutions fit the latter task better) Feature table # Feature Obsidian TriliumNext Markdown editor ✅ ✅ Nested notes ⚙️ via folders ✅ hierarchically Tags and links ✅ ✅ Graph view ✅ ⚙️ (via the map) Embedded images / files ✅ ✅ Note attributes ⚙️ via plugins ✅ built-in Versioning ⚙️ via Git / plugins ✅ built-in Templates ✅ via plugins ✅ built-in API / scripts ⚙️ via plugins ✅ built-in JS API Diagrams / flowcharts ⚙️ via plugins ✅ built-in Themes / customization ✅ many themes ⚙️ limited Web interface ⚙️ (via Publish) ✅ out of the box Self-Hosting ⚙️ (via Git/Sync) ✅ primary scenario Choosing: who should pick what # Scenario Recommendation Getting started quickly, just writing notes 🟩 Obsidian Building a complex knowledge base with hierarchy 🟩 TriliumNext Working with Markdown and external editors 🟩 Obsidian Self-Hosting, privacy, control 🟩 TriliumNext Built-in sync out of the box across all clients 🟩 TriliumNext Conclusion # Obsidian is ideal for those who want a flexible, aesthetically pleasing, and easy-to-learn note-taking system.\nTriliumNext is better suited for those aiming to build a structured knowledge base with full control over their data and powerful built-in capabilities.\nA tip from prohomelab: if you want to start with a tool that has plenty of videos to learn from, start with Obsidian.\nIf you need powerful hierarchy and templates, and the (frankly) unnecessary prettiness just annoys you - switch to TriliumNext.\nUseful links # Official Obsidian website TriliumNext repository on GitHub TriliumNext documentation Obsidian community TriliumNext review on AndroidAuthority ","date":"October 31, 2025","externalUrl":null,"permalink":"/en/posts/trilium-vs-obsidian/","section":"Posts","summary":"A detailed comparison of Obsidian and TriliumNext: two powerful systems for organizing notes and a personal knowledge base. Which one should you choose for your workflow?","title":"Obsidian vs TriliumNext - a comparison of knowledge management systems","type":"posts"},{"content":"","date":"October 31, 2025","externalUrl":null,"permalink":"/en/tags/trilium/","section":"Tags","summary":"","title":"Trilium","type":"tags"},{"content":" Trilium - a powerful personal knowledge system under your control # Introduction: why you need Trilium - and why you need PKM tools at all # In an age of information overload, we suffer not so much from a lack of knowledge as from the sheer volume of information that piles up on us every day, and from the chaos that this volume creates: scattered ideas, lost connections, forgotten context, and other horrors of digitalization. Not to mention attempts to manipulate you by telling you that your brain wasn\u0026rsquo;t made to hold anything in memory - as if you were some kind of computer with a limited amount of RAM. (Spoiler, spoiler - that\u0026rsquo;s not true.) Tools exist to solve this problem, and the community has affectionately dubbed them Personal Knowledge Management (PKM) systems - personal knowledge bases.\nSuch systems let you:\ncollect scattered notes, ideas, links, and drafts in one place; integrate different formats (text, images, diagrams, tables, code) in a single database; find connections between notes via links, graphs, search, and attributes; grow knowledge - not just record facts, but connect, deepen, and reassemble them; export / back up - so you don\u0026rsquo;t depend on someone else\u0026rsquo;s cloud. Classic tools like Obsidian or Notion give you either a \u0026ldquo;file-based\u0026rdquo; approach (Markdown + plugins, as with Obsidian) or a cloud ecosystem with limitations. Given everything that\u0026rsquo;s happened recently, being cloud-based is itself a limitation - arguably even a barrier by now. Obsidian, Notion, and Joplin are all good, but Trilium goes further, offering a hybrid approach: a powerful tree structure, database flexibility, and the privacy of a self-hosted solution. That said, keep in mind that Obsidian and Notion aren\u0026rsquo;t open-source, and while Joplin is popular, it\u0026rsquo;s also far from perfect.\nThe hero of today\u0026rsquo;s article, Trilium, is an actively community-developed successor to the original project started by developer zadam. For a while the community fork lived under the name TriliumNext, but in 2025 the author handed the original repository and name back to it - so it\u0026rsquo;s simply Trilium again, not a fork.\nTrilium is also not \u0026ldquo;just notes\u0026rdquo; - it\u0026rsquo;s a system in which a note is a data object with fields, templates, relations, attributes, and visual interfaces. When your database grows to hundreds or thousands of notes, that difference becomes especially noticeable.\nWhat Trilium is: a brief overview of version 0.104.1 (the current version as of this article\u0026rsquo;s update date) # Trilium\u0026rsquo;s main features: # Notes can be organized into a tree of arbitrary depth. One note can be placed in multiple locations in the tree. An advanced WYSIWYG note editor, including tables, images, and math formulas with automatic Markdown formatting Support for editing code notes, including syntax highlighting Fast and simple navigation between notes, full-text search, and note hoisting Seamless note revision management Note attributes can be used to organize notes, build queries, and create advanced scripts Direct OpenID and TOTP integration for more secure login Synchronization with your own sync server there\u0026rsquo;s a third-party hosting service for the sync server Publishing notes to a public space Reliable note encryption with per-note granularity Creating diagrams based on Excalidraw (the \u0026ldquo;canvas\u0026rdquo; note type) Relation maps and link maps (note maps) for visualizing notes and their relationships Mind maps based on Mind Elixir Geo maps with location markers and GPX tracks Scripting - see Advanced Showcases REST API for automation Scales well both in terms of usability and performance when handling more than 100,000 notes. A touch-optimized mobile interface for smartphones and tablets A built-in dark theme with support for custom themes Evernote and Markdown import/export A Web Clipper for conveniently saving web content A customizable UI (sidebar buttons, custom widgets, \u0026hellip;) Metrics together with a Grafana dashboard For more information about Trilium, you can also read:\nawesome-trilium for third-party themes, scripts, plugins, and more. TriliumRocks! - learning materials, guides, and more. Trilium turns notes into data objects - each entry can have attributes, relations, a template, and visualizations. This makes the system feel closer to a knowledge base than a simple set of files.\n-\u0026ndash;\nInstalling and configuring Trilium # Below is my docker-compose file, assuming I\u0026rsquo;m using the Traefik reverse proxy\nservices: trilium: # Define a service named \u0026#34;trilium\u0026#34; container_name: trilium # Docker container name (for convenience) image: triliumnext/trilium:v0.104.1 # Official Trilium image, pinning a specific version. Don\u0026#39;t use latest - the official docs explicitly warn that the tag can silently bump the minor version and break sync restart: always # The container will restart automatically on failure or Docker reboot environment: # Environment variables passed into the container TRILIUM_NETWORK_TRUSTEDREVERSEPROXY: 172.18.0.0/16 # Trusted network for the reverse proxy TRILIUM_DATA_DIR: /home/node/trilium-data # Path to the directory where Trilium stores its data inside the container TZ: ${TZ} # Set the timezone from an environment variable (usually defined in .env) TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHBASEURL: \u0026#34;https://trilium.domain.ru\u0026#34; # Base URL for OIDC callbacks (Trilium needs to know its public address) TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTID: ${TRILIUM_CLIENT_ID} # OAuth client ID (taken from .env or a secret) TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHCLIENTSECRET: ${TRILIUM_CLIENT_SECRET} # OAuth client secret (also from .env) TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERBASEURL: \u0026#34;https://auth.domain.ru/application/o/trilium\u0026#34; # Identity Provider address (Authentik in this case) TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERNAME: \u0026#34;Authentik\u0026#34; # Name of the auth provider shown in the Trilium UI TRILIUM_MULTIFACTORAUTHENTICATION_OAUTHISSUERICON: \u0026#34;https://cdn.jsdelivr.net/gh/selfhst/icons/svg/authentik.svg\u0026#34; # Auth provider icon (a nice UI touch) volumes: # Mount local directories into the container - /home/user/docker/trilium:/home/node/trilium-data # Main data volume (replaces Trilium\u0026#39;s built-in directory) # If you want the container to inherit the system timezone, uncomment: # - /etc/localtime:/etc/localtime:ro # Mount the system\u0026#39;s local time into the container (read-only) networks: proxy: # Attach the container to the external \u0026#34;proxy\u0026#34; network (used by Traefik) labels: # Labels for Traefik integration (reverse proxy) - \u0026#34;traefik.enable=true\u0026#34; # Enable Traefik processing for the container - \u0026#34;traefik.http.routers.trilium.entrypoints=web\u0026#34; # Define the HTTP entrypoint (port 80) - \u0026#34;traefik.http.routers.trilium.rule=Host(`trilium.domain.ru`)\u0026#34; # Traffic to this domain is routed to this container - \u0026#34;traefik.http.middlewares.trilium-https-redirect.redirectscheme.scheme=https\u0026#34; # Middleware to redirect HTTP to HTTPS - \u0026#34;traefik.http.routers.trilium.middlewares=trilium-https-redirect\u0026#34; # Apply the redirect middleware to the HTTP route - \u0026#34;traefik.http.routers.trilium-secure.entrypoints=websecure\u0026#34; # Define the HTTPS entrypoint (port 443) - \u0026#34;traefik.http.routers.trilium-secure.rule=Host(`trilium.domain.ru`)\u0026#34; # HTTPS route for the same domain - \u0026#34;traefik.http.routers.trilium-secure.tls=true\u0026#34; # Enable TLS (HTTPS) - \u0026#34;traefik.http.routers.trilium-secure.service=trilium\u0026#34; # Bind the HTTPS route to the Trilium service - \u0026#34;traefik.http.services.trilium.loadbalancer.server.port=8080\u0026#34; # Specify the internal port Trilium listens on in the container - \u0026#34;traefik.docker.network=proxy\u0026#34; # Tell Traefik to look for the container in the \u0026#34;proxy\u0026#34; network networks: proxy: # Definition of the external network for talking to Traefik external: true # The network was already created earlier (don\u0026#39;t recreate) and also the variables file\n# Timezone TZ=Europe/Moscow # OAuth2 (Authentik) TRILIUM_CLIENT_ID=client-id TRILIUM_CLIENT_SECRET=client-secret Note Trilium is also supported on Kubernetes, via Cloudron, HomelabOS, a NixOS module, and others.\nKeep in mind that Traefik versions 3.6.4 and above had some minor breaking changes. If you use Traefik as your reverse proxy, you need to add the following block to your static configuration file\nwebsecure: # Entrypoint for HTTPS (port 443) address: \u0026#34;:443\u0026#34; # Listen on port 443 http: # HTTP settings for HTTPS encodedCharacters: # Allowed encoded characters (important for Trilium) allowEncodedSlash: true # Allow %2F allowEncodedPercent: true # Allow %25 allowEncodedHash: true # Allow %23 Configuration location # By default, config.ini, the database, and other important Trilium files are stored in the data directory. If you want to use a different location, you can set the TRILIUM_DATA_DIR environment variable, for example:\nexport TRILIUM_DATA_DIR=/home/myuser/data/my-trilium-data\nDisabling / changing the upload limit # If you run into the default 250 MB upload limit and want to raise it, you can set the TRILIUM_NO_UPLOAD_LIMIT=true environment variable to disable the limit entirely:\nexport TRILIUM_NO_UPLOAD_LIMIT=true Or, if you just want to raise the limit to something bigger than 250 MB, you can use the MAX_ALLOWED_FILE_SIZE_MB variable, for example:\nexport MAX_ALLOWED_FILE_SIZE_MB=450 Synchronization # Trilium is an \u0026ldquo;offline-first\u0026rdquo; note-taking app: it stores all data locally on the desktop client, or on the so-called server installation described above. However, Trilium also lets you set up synchronization with a server instance, allowing multiple desktop clients to sync with a central server and vice versa. This creates a \u0026ldquo;star\u0026rdquo; topology. More details are in the synchronization documentation\nIn this configuration, a central server (called the sync server) and several client (or desktop) instances synchronize with the sync server. Once configured, synchronization becomes automatic and continuous, requiring no manual intervention.\nNote! Obsidian? Never heard of it Setting up synchronization # Security considerations # Secure server setup is critically important and may seem complicated at first. To ensure security and prevent potential vulnerabilities, it\u0026rsquo;s important to use a valid SSL certificate (HTTPS) rather than an unencrypted HTTP connection.\nSyncing a desktop instance with the sync server # This method is used when you already have a desktop instance of Trilium and want to set up a sync server on your web hosting or simply on a Docker machine.\nDeploy the server: make sure the server instance is deployed but not initialized. Desktop configuration: open the desktop instance, go to \u0026ldquo;Options\u0026rdquo; -\u0026gt; the \u0026ldquo;Sync\u0026rdquo; tab -\u0026gt; \u0026ldquo;Sync Configuration,\u0026rdquo; and enter your sync server\u0026rsquo;s address in the \u0026ldquo;Server instance address\u0026rdquo; field. Click \u0026ldquo;Save.\u0026rdquo; 3. Testing the sync: click the \u0026ldquo;Test Sync\u0026rdquo; button to check the connection to the sync server. On success, the client will start transferring all data to the server. This may take a while, but you can keep using Trilium in the meantime. Periodically check the server to confirm sync has completed. Once done, you\u0026rsquo;ll see the server login screen.\nSyncing the sync server with a desktop app instance # This method is used when you already have a sync server (our instance, set up in our homelab) and want to configure a new desktop instance to sync with it.\nDesktop setup: follow the instructions on the desktop installation page. Initial configuration: when prompted, choose the option to sync with the sync server. Server details: configure the Trilium server address and enter the correct username and password for authentication. Finish setup: click \u0026ldquo;Finish Setup.\u0026rdquo; On success, you\u0026rsquo;ll see the following screen: Mobile frontend # Trilium (server version) has a mobile web interface optimized for touch devices - smartphones and tablets. It activates automatically upon login, based on browser detection.\nThe mobile interface has limited functionality compared to the full-featured desktop interface.\nNote that this isn\u0026rsquo;t an Android/iOS app, just a mobile-friendly web page hosted on the server.\nLimitations # The mobile interface provides only some of the full desktop interface\u0026rsquo;s features:\nyou can browse the entire note tree, read and edit all note types, but can only create text notes reading and editing protected notes is possible, but creating them is not supported editing options are not supported note cloning is not supported uploading attachments is not supported Web clipper # Trilium Web Clipper is a browser extension that lets you clip text, screenshots, entire pages, and short notes and save them directly into Trilium Notes.\nThe project is hosted here.\nFirefox and Chrome are supported, but the Chrome build should also work in other Chromium-based browsers.\nI use this version\nFunctionality # select text and clip it via the right-click context menu click an image or link and save it via the context menu save an entire page from the popup or context menu save a screenshot (with a crop tool) from the popup or context menu create a short text note from the popup Trilium will save these clippings as a new child note under the \u0026ldquo;Clipper Inbox\u0026rdquo; note.\nBy default this is a day note, but you can override this.\nIf there are multiple clippings from the same page (and on the same day), they\u0026rsquo;ll be added to the same note.\nConfiguration # The extension needs to connect to a running Trilium instance. By default it scans a port range on the local machine to find a Trilium desktop instance.\nYou can also configure the server address if you\u0026rsquo;re not running the desktop app, or want it to work without the desktop app running.\nSince this article has already gotten quite long, I\u0026rsquo;ll probably continue covering the app\u0026rsquo;s features in a separate article.\n","date":"October 30, 2025","externalUrl":null,"permalink":"/en/posts/trilium/","section":"Posts","summary":"A step-by-step guide to installing and configuring Trilium for organizing notes and knowledge bases on a personal server. Covers installation via Docker, web interface setup, users, and recommendations for effective note management.","title":"Trilium — installing and setting up a note-taking system","type":"posts"},{"content":"","date":"October 29, 2025","externalUrl":null,"permalink":"/en/categories/vaultwarden/","section":"Categories","summary":"","title":"Vaultwarden","type":"categories"},{"content":"","date":"October 29, 2025","externalUrl":null,"permalink":"/en/tags/vaultwarden/","section":"Tags","summary":"","title":"Vaultwarden","type":"tags"},{"content":" Vaultwarden # Installing Vaultwarden # Note Article updated: added an advanced configuration with SSO (Authentik), push notifications, and moving secrets into an .env file — this is exactly how the instance on my server is set up now.\nWhat is a password manager - briefly # A password manager is an app that securely stores your logins, passwords, notes, and other secrets in encrypted form and helps automatically fill in data when logging into sites/apps. Benefits: strong unique passwords for each service, random password generation, sync across devices, a centralized store for passwords and SSH keys, and a change history.\nWhat is Vaultwarden # Vaultwarden is a lightweight, fast, Bitwarden-compatible server implementation (written in Rust) that implements the Bitwarden API and lets you use official Bitwarden clients (browser extensions, mobile/desktop apps) with your own server. Vaultwarden is designed for self-hosted deployment (containers, Docker Compose, Kubernetes, etc.).\nWhy self-hosted # Briefly - the key benefits of self-hosted Vaultwarden:\nControl over your data: the database and backups are under your control, and only yours, not in some third party\u0026rsquo;s cloud. Privacy: no metadata/backup copies are sent to external services. You, and only you, control your data. Flexibility and integration: you can connect LDAP/SMTP/an external DB, SSO via your own identity provider, set up backups, use your own TLS (reverse proxy), and so on. Savings and simplicity: Vaultwarden is lighter and cheaper on resources than the upstream Bitwarden Server. Downsides/risks: you\u0026rsquo;re responsible for security yourself (updates, TLS, backups, firewall configuration, secret rotation). There\u0026rsquo;s one point here that some might find debatable, though. For some reason, people believe Bitwarden is more secure because it\u0026rsquo;s a commercial product. At first glance that sounds logical. But in reality, the cloud services of companies are always under attack, and sometimes they let one through. Bitwarden itself has had leaks more than once, and users of its cloud have often had their accounts hijacked. Strange as it may seem, you end up protecting your own Vaultwarden instance far more carefully. And that\u0026rsquo;s not even counting the fact that, no offense, you personally aren\u0026rsquo;t really an interesting target in the first place.\nShort deployment plan (what we\u0026rsquo;ll do) # Start with a basic docker-compose.yml - a minimal working setup. Cover the advanced configuration: secrets in .env, SSO via Authentik, push notifications, Rocket/logging tuning - the setup currently running for me. Set up a reverse proxy and TLS. Walk through the admin panel, user registration, and organizations. Cover backups and common mistakes. Basic installation # If you just need a working server without SSO and extra settings - this setup is enough. Further in the article there\u0026rsquo;s also an advanced version, but it\u0026rsquo;s easier to start with this one.\nservices: vaultwarden: # Definition of the Vaultwarden service - the main password manager container. container_name: vaultwarden # Container name in Docker - convenient for commands and logs. image: vaultwarden/server:latest # Official Vaultwarden image from Docker Hub (written in Rust). restart: unless-stopped # The container will automatically restart if it crashes, but not after a manual stop. volumes: - /path/to/bind/mount/:/data/ # Mount a local host directory into /data inside the container. # This is where the database, attachments, and Vaultwarden config are stored. environment: - SIGNUPS_ALLOWED=false # Disallow new user registrations (false) - improves security. - ADMIN_TOKEN=replace_with_a_hashed_token # See the hashing section below — don\u0026#39;t store the token in plain text. - WEBSOCKET_ENABLED=true # Enable WebSocket - Bitwarden clients get instant updates. - DOMAIN=https://vaultwarden.domain.ru # Specify the domain — needed for correct links (password reset, TOTP, etc.) - TZ=Europe/Moscow # Set the timezone — correct time in logs and notifications. networks: - proxy # Attach the container to Traefik\u0026#39;s external network so the proxy can discover it. labels: - \u0026#34;traefik.enable=true\u0026#34; # --- HTTP → HTTPS redirect --- - \u0026#34;traefik.http.routers.vaultwarden.entrypoints=web\u0026#34; - \u0026#34;traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.domain.ru`)\u0026#34; - \u0026#34;traefik.http.middlewares.vaultwarden-https-redirect.redirectscheme.scheme=https\u0026#34; - \u0026#34;traefik.http.routers.vaultwarden.middlewares=vaultwarden-https-redirect\u0026#34; # --- HTTPS (secure) --- - \u0026#34;traefik.http.routers.vaultwarden-secure.entrypoints=websecure\u0026#34; - \u0026#34;traefik.http.routers.vaultwarden-secure.rule=Host(`vaultwarden.domain.ru`)\u0026#34; - \u0026#34;traefik.http.routers.vaultwarden-secure.tls=true\u0026#34; - \u0026#34;traefik.http.routers.vaultwarden-secure.service=vaultwarden\u0026#34; # --- Backend settings --- - \u0026#34;traefik.http.services.vaultwarden.loadbalancer.server.port=80\u0026#34; - \u0026#34;traefik.docker.network=proxy\u0026#34; security_opt: - no-new-privileges:true # The container won\u0026#39;t be able to escalate its privileges within the system. networks: proxy: external: true # Use the external Docker network that Traefik already uses. Notes on the basic file # ADMIN_TOKEN - the token for logging into the admin panel (/admin). Without it, the panel is inaccessible. For how to hash the token properly, see the \u0026ldquo;Secure ADMIN_TOKEN\u0026rdquo; section below. SIGNUPS_ALLOWED=false - recommended if the server is exposed externally. Only allow true while creating the first account, then turn it off. WEBSOCKET_ENABLED=true - real-time sync across clients. The reverse proxy must support proxying Upgrade: websocket. Advanced configuration: .env, SSO, and push notifications # Once the service picks up users, you\u0026rsquo;ll want to get secrets out of the compose file, add single sign-on through your own identity provider (mine is Authentik), and get push notifications on mobile clients instead of just polling/websocket. Here\u0026rsquo;s the configuration that\u0026rsquo;s currently running for me.\ndocker-compose.yml # services: vaultwarden: container_name: vaultwarden image: vaultwarden/server:latest restart: unless-stopped volumes: - /path/to/docker/vaultwarden/data:/data - /path/to/docker/vaultwarden/logs:/data/logs ports: - 18083:80 environment: - ADMIN_TOKEN=${VAULTWARDEN_ADMIN_TOKEN} - SIGNUPS_ALLOWED=${VAULTWARDEN_SIGNUPS_ALLOWED} - SIGNUPS_VERIFY=${VAULTWARDEN_SIGNUPS_VERIFY} - INVITATIONS_ALLOWED=${VAULTWARDEN_INVITATIONS_ALLOWED} - WEBSOCKET_ENABLED=true - ROCKET_ENV=prod - ROCKET_WORKERS=10 - TZ=${VAULTWARDEN_TZ} - LOG_LEVEL=error - EXTENDED_LOGGING=true - DOMAIN=${VAULTWARDEN_BASE_URL} - SMTP_HOST=${VAULTWARDEN_EMAIL__HOST} - SMTP_PORT=${VAULTWARDEN_EMAIL__PORT} - SMTP_FROM=${VAULTWARDEN_EMAIL__USERNAME} - SMTP_USERNAME=${VAULTWARDEN_EMAIL__USERNAME} - SMTP_PASSWORD=${VAULTWARDEN_EMAIL__PASSWORD} - SMTP_SECURITY=${VAULTWARDEN_EMAIL__SECURITY} - SSO_ENABLED=true - SSO_AUTHORITY=https://authentik.domain.ru/application/o/vaultwarden/ - SSO_CLIENT_ID=${VAULTWARDEN_SSO_CLIENT_ID} - SSO_CLIENT_SECRET=${VAULTWARDEN_SSO_CLIENT_SECRET} - SSO_SCOPES=\u0026#34;openid email profile offline_access\u0026#34; - SSO_ALLOW_UNKNOWN_EMAIL_VERIFICATION=false - SSO_CLIENT_CACHE_EXPIRATION=0 - SSO_ONLY=false # true - completely disables master-password login, SSO only - SSO_SIGNUPS_MATCH_EMAIL=true # the first SSO login is linked to an existing account by email - PUSH_ENABLED=true - PUSH_INSTALLATION_ID=${VAULTWARDEN_PUSH_INSTALLATION_ID} - PUSH_INSTALLATION_KEY=${VAULTWARDEN_PUSH_INSTALLATION_KEY} - PUSH_RELAY_URI=https://api.bitwarden.eu - PUSH_IDENTITY_URI=https://identity.bitwarden.eu networks: - vaultwarden # The reverse proxy is configured separately — see the Traefik/Nginx section below. # Example Traefik labels (if the container is on the same network as the proxy): #labels: # - \u0026#34;traefik.enable=true\u0026#34; # - \u0026#34;traefik.http.routers.vaultwarden.entrypoints=web\u0026#34; # - \u0026#34;traefik.http.routers.vaultwarden.rule=Host(`vaultwarden.domain.ru`)\u0026#34; # - \u0026#34;traefik.http.middlewares.vaultwarden-https-redirect.redirectscheme.scheme=https\u0026#34; # - \u0026#34;traefik.http.routers.vaultwarden.middlewares=vaultwarden-https-redirect\u0026#34; # - \u0026#34;traefik.http.routers.vaultwarden-secure.entrypoints=websecure\u0026#34; # - \u0026#34;traefik.http.routers.vaultwarden-secure.rule=Host(`vaultwarden.domain.ru`)\u0026#34; # - \u0026#34;traefik.http.routers.vaultwarden-secure.tls=true\u0026#34; # - \u0026#34;traefik.http.routers.vaultwarden-secure.service=vaultwarden\u0026#34; # - \u0026#34;traefik.http.services.vaultwarden.loadbalancer.server.port=80\u0026#34; # - \u0026#34;traefik.docker.network=proxy\u0026#34; security_opt: - no-new-privileges:true networks: vaultwarden: external: true Tip In this version the container publishes port 18083:80 directly, and the Traefik labels are commented out. This is handy if the reverse proxy is configured separately (for example, via a separate Traefik config file rather than Docker labels), or if traffic is routed through a different proxy. If you\u0026rsquo;re using labels as in the basic version above, uncomment that block and remove the external port publication, keeping it internal only.\n.env file # Secrets and things that often change between environments go into .env next to docker-compose.yml:\nVAULTWARDEN_ADMIN_TOKEN=\u0026lt;hashed token, see section below\u0026gt; # Temporary settings for the first registration VAULTWARDEN_SIGNUPS_ALLOWED=false VAULTWARDEN_SIGNUPS_VERIFY=true VAULTWARDEN_INVITATIONS_ALLOWED=true # Email for notifications VAULTWARDEN_EMAIL__HOST=smtp.gmail.com VAULTWARDEN_EMAIL__PORT=465 VAULTWARDEN_EMAIL__USERNAME=\u0026lt;your email/SMTP login\u0026gt; VAULTWARDEN_EMAIL__PASSWORD=\u0026#34;\u0026lt;app password\u0026gt;\u0026#34; VAULTWARDEN_EMAIL__SECURITY=force_tls # options: starttls, force_tls, off # SSO (Authentik) VAULTWARDEN_SSO_CLIENT_ID=\u0026lt;client id from Authentik\u0026gt; VAULTWARDEN_SSO_CLIENT_SECRET=\u0026lt;client secret from Authentik\u0026gt; # Push notifications VAULTWARDEN_PUSH_INSTALLATION_ID=\u0026lt;installation id from bitwarden.com/host\u0026gt; VAULTWARDEN_PUSH_INSTALLATION_KEY=\u0026lt;installation key from bitwarden.com/host\u0026gt; # Locale VAULTWARDEN_TZ=Europe/Moscow # Base URL (needed for email confirmation and SSO redirect to work correctly) VAULTWARDEN_BASE_URL=https://vaultwarden.domain.ru Warning .env contains passwords and secrets in plain text on disk. Be sure to add it to .gitignore if you keep your compose files in a git repository, and restrict permissions on the file (chmod 600 .env).\nWhat changed compared to the basic version # Parameter Why ROCKET_ENV=prod Explicitly sets production mode for the Rocket web framework Vaultwarden is built on - less debug output, slightly different logging behavior. ROCKET_WORKERS=10 The number of worker threads handling requests. The default is modest; for a server with several active users/organizations it makes sense to increase it. LOG_LEVEL=error + EXTENDED_LOGGING=true Only errors are logged, but in an extended format (timestamps, module) - convenient for debugging without cluttering the logs with noise. /data/logs as a separate volume Logs are written to a file, not just to the container\u0026rsquo;s stdout - convenient for shipping them, e.g., to Promtail/Alloy for a monitoring stack. SIGNUPS_VERIFY=true Requires confirming your email upon registration - relevant when INVITATIONS_ALLOWED=true and you\u0026rsquo;re inviting people directly. Setting up SSO via Authentik # Vaultwarden supports login via OpenID Connect - you can use Authentik, Keycloak, Authelia, or any other OIDC-compatible provider. The general logic is the same, shown below using Authentik as the example.\nIn Authentik, create a new OAuth2/OpenID Provider with a redirect URI like https://vaultwarden.stilicho.ru/identity/connect/oidc-signin. Create an Application, link it to the provider from step 1, and set a slug (in my case - vaultwarden, hence SSO_AUTHORITY=.../application/o/vaultwarden/). Copy the Client ID and Client Secret - these go into VAULTWARDEN_SSO_CLIENT_ID and VAULTWARDEN_SSO_CLIENT_SECRET. In the compose file, set SSO_ENABLED=true and specify SSO_AUTHORITY - this is the base URL of your OIDC provider; Vaultwarden will pick up .well-known/openid-configuration on its own. SSO_SIGNUPS_MATCH_EMAIL=true - if a user already has a Vaultwarden account, the first SSO login gets linked to it by email instead of creating a duplicate. Leave SSO_ONLY as false until you\u0026rsquo;ve confirmed SSO login definitely works - otherwise you risk locking yourself out if something goes wrong on the provider\u0026rsquo;s side. Important After your first successful SSO login, also verify login with the regular master password (if SSO_ONLY=false) - this is your \u0026ldquo;emergency exit\u0026rdquo; in case Authentik becomes unavailable.\nPush notifications # PUSH_ENABLED enables push notifications on Bitwarden mobile clients (instant appearance of one-time login codes, new-device notifications, etc.) without constant polling.\nFor this you need PUSH_INSTALLATION_ID and PUSH_INSTALLATION_KEY - issued for free at bitwarden.com/host after registering a self-hosted installation. In the example, PUSH_RELAY_URI/PUSH_IDENTITY_URI point to the European relay (api.bitwarden.eu / identity.bitwarden.eu) - if your users aren\u0026rsquo;t in the EU, you can use the global relay (api.bitwarden.com / identity.bitwarden.com).\nSecure ADMIN_TOKEN # By default you can simply generate a random, complex token in any password generator and put it in ADMIN_TOKEN, but storing it as plain text is insecure - Vaultwarden will warn you about it both in the logs and in the admin panel itself.\nThe simplest way to hash the token is Vaultwarden\u0026rsquo;s own built-in command (available since version 1.28), which requires no extra packages:\ndocker exec vaultwarden /vaultwarden hash --preset owasp The command asks for the password interactively and outputs a ready string like $argon2id$v=19$m=...$... - that\u0026rsquo;s what you paste into ADMIN_TOKEN (in the .env file you don\u0026rsquo;t need to escape $; but if you write the value directly into docker-compose.yml without .env, each $ needs to be doubled: $$, otherwise Compose will try to interpret them as environment variables).\nDetails are in the Vaultwarden wiki.\nAfter that, you can (re)start the container:\ndocker compose up -d Keep in mind that the /admin panel is the most attractive target for brute-forcing; if you want to lock it down with extra rate-limiting or ban scanners at the Traefik level, see the article on middlewares in Traefik and CrowdSec.\nFirst login to the admin panel # After the container starts, you can check its logs, for example via Portainer or the docker logs vaultwarden command.\nIf everything\u0026rsquo;s fine, the app won\u0026rsquo;t complain - the token value is properly hashed. Otherwise you\u0026rsquo;ll see a warning that the token is stored as plain text and that this is insecure (this by itself doesn\u0026rsquo;t affect functionality, but it weakens the admin panel\u0026rsquo;s protection).\nTo reach the admin panel, type the address of your Vaultwarden into the browser\u0026rsquo;s address bar and be sure to add /admin at the end.\nTo confirm, enter the admin password and you land in the panel. Select the General settings tab - this is the central configuration section.\nRight at the top there\u0026rsquo;s a reminder that any values entered in the admin settings will override environment variable values (for example, mail server settings) or the app\u0026rsquo;s own settings. Values that will be overridden are highlighted in yellow.\nThe \u0026ldquo;General settings\u0026rdquo; section - a detailed overview # Domain # Description: The main domain Vaultwarden is accessible on. Example: https://vaultwarden.stilicho.ru Purpose: Used in links (invitations, password reset, email notifications, SSO redirect). Important: if you change the domain, also update WEBSOCKET_ADDRESS and the redirect URI in your OIDC provider\u0026rsquo;s settings. WebSocket Address # Description: The WebSocket address for syncing Bitwarden clients. Example: wss://vault.stilicho.ru/notifications/hub Purpose: Enables instant sync (for example, if a new password is added from another device). Note: If you use Traefik or another proxy - make sure to forward /notifications/hub. Web Vault Enabled # Description: Enables or disables the web vault interface. Default: enabled. Why disable it: if you want to use Vaultwarden only through the Bitwarden Desktop/Mobile clients. User Registration (Allow new signups) # Environment variable: SIGNUPS_ALLOWED Options: true - anyone can register; false - only manually (the admin creates users via /admin or invitations). Tip: disable it on a public server. Only leave it enabled temporarily to register the first account. Require email verification on signups # Variable: SIGNUPS_VERIFY Recommendation: enable it when SMTP is configured - especially if invites are allowed (INVITATIONS_ALLOWED=true), to rule out email typos. Invitation (Allow invitations) # Variable: INVITATIONS_ALLOWED Recommendation: leave it enabled if you use Organizations - otherwise no one will be able to join. SMTP Enabled # Variables: SMTP_* Recommendation: set up SMTP before creating organizations or before a password reset is needed. SSO Enabled # Variable: SSO_ENABLED Description: enables login via OpenID Connect. In the admin UI you can view the current connection status with the provider and diagnostics - useful if something\u0026rsquo;s off with SSO_AUTHORITY. E-mail Domain Whitelist # Example: stilicho.ru,prohomelab.com Purpose: restrict registration to your own/corporate domains. Allow password hints # Recommendation: can be disabled so as not to give a potential attacker any hints. YubiKey OTPs Enabled # Variables: YUBICO_CLIENT_ID, YUBICO_SECRET_KEY Purpose: two-factor authentication via YubiKey hardware keys. WebSocket Notifications Enabled # Note: requires a properly configured reverse proxy. WebSocket Docs Admin Token # Description: shows the current token used to log into the admin panel. It can only be changed via the environment variable (ADMIN_TOKEN in .env); the panel doesn\u0026rsquo;t let you change it \u0026ldquo;on the fly\u0026rdquo; without restarting the container. Disable Two-Factor remember # Recommendation: enable on public servers for better security. Note: since recent Vaultwarden versions, \u0026ldquo;remembered\u0026rdquo; 2FA tokens are valid for no more than 30 days regardless. Important One of the most important sections is the mail settings under SMTP EMAIL SETTINGS. If you plan to invite users (family members, employees), these settings are mandatory.\nThe rest of the settings are up to you, but I\u0026rsquo;d turn off simple uncontrolled registration in the app. Disabling registration doesn\u0026rsquo;t affect invitations or SSO.\nThe Users section # The \u0026ldquo;Users\u0026rdquo; table shows a list of all vault users, their status, confirmation level, and activity. From here you can also invite new users and manually confirm SSO accounts if SSO_SIGNUPS_MATCH_EMAIL didn\u0026rsquo;t kick in automatically.\nWhat is an Organization # An Organization is a group of users who can share certain items (logins, passwords, secure notes, etc.). Analogous to a corporate or family vault in Bitwarden Cloud.\nBasic idea # You have a personal vault, visible only to you. Within an Organization you can create shared collections, for example: \u0026ldquo;DevOps\u0026rdquo; - CI/CD passwords, SSH keys, API tokens \u0026ldquo;Marketing\u0026rdquo; - access to social media and ad accounts \u0026ldquo;Family\u0026rdquo; - shared subscriptions (Netflix, Spotify, etc.) How it works # The admin creates an organization (e.g., \u0026ldquo;ProHomelab\u0026rdquo;). Adds members by email (they need an account on the same server - via regular registration, invite, or SSO). Creates Collections (categories for shared data). Assigns access rights to each collection (read, write, admin). Users receive these entries in their Bitwarden client (web, desktop, mobile). Example structure # Organization: ProHomelab ├── Collection: Infrastructure │ ├── Proxmox login │ ├── Traefik dashboard │ └── Grafana API key ├── Collection: Media │ ├── Jellyfin admin │ └── Audiobookshelf credentials Role types # Owner - full control over the organization. Admin - manages users and collections. Manager - manages only their own collections. User - uses granted access, without managing the structure. Important details # Organizations aren\u0026rsquo;t required for personal use. Invitations require INVITATIONS_ALLOWED enabled and SMTP configured. You can create several organizations on one server. Personal encryption keys are supported - the admin can\u0026rsquo;t see the contents of members\u0026rsquo; passwords. Registering the first user # Go to your Vaultwarden\u0026rsquo;s address (in my case vaultwarden.stilicho.ru) and choose Create Account.\nEnter an email and a nickname.\nWarning To register the very first user, you need to temporarily allow simple registration (SIGNUPS_ALLOWED=true). After creating the first (admin) account - set it back to false.\nIf you have SSO enabled with SSO_SIGNUPS_MATCH_EMAIL=true, it\u0026rsquo;s still easier to create the first user via regular registration or an invite, and then just log in via SSO afterward - the linking will happen automatically by email.\nBy default the password must be at least 12 characters, and Vaultwarden checks it for complexity and offers to check whether it\u0026rsquo;s been leaked (whether such a password has been compromised before).\nAfter that you land in the vault.\nAt the top there\u0026rsquo;s a hint about the first three steps: create an account, install the browser extension, import data from another password manager. The export format depends on the specific source app, but the general principle is the same: export a file there, import it here.\nUser Settings # User settings are what a regular Vaultwarden user sees after logging into the Web Vault interface at https://vaultwarden.\u0026lt;your-domain\u0026gt;.ru.\nLet\u0026rsquo;s look at the Vaults section - the \u0026ldquo;heart\u0026rdquo; of the whole system, where passwords, tokens, notes, and other secrets are stored and managed.\n💡 To avoid confusion:\nVaults - the personal store (and shared ones via Organizations). Settings - vault behavior settings. Admin Panel (/admin) - server-side parameters. Basic structure # 1. Items (vault entries) # Type Purpose Example Login Login + password + URL GitHub site, SSH panel, Grafana Card Bank card details Visa, MasterCard Identity Personal data Full name, address, email Secure Note Free-form text SSH key, API token, config Each item contains a name, type, fields (username, password, URL, etc.), optionally a TOTP code, attachments, notes, and a link to an Organization/Collection.\n2. Collections # If you\u0026rsquo;re part of an Organization, a list of Collections - shared folders with entries available to a group of users - will appear in the left panel. Without an organization, these sections aren\u0026rsquo;t shown.\n3. Navigation tabs # Tab Purpose All Items All entries, personal and shared Favorites Items marked with a \u0026ldquo;star\u0026rdquo; Folders Personal folders (for the user\u0026rsquo;s own structure only) Trash Deleted entries that can be restored Organizations Access to shared vaults 4. Adding new entries # The + New Item button opens the entry creation form. Options include \u0026ldquo;Generate password\u0026rdquo; (built-in generator), \u0026ldquo;Add TOTP\u0026rdquo; (one-time 2FA code), \u0026ldquo;Attach file\u0026rdquo; (if ENABLE_ATTACHMENTS=true is enabled).\n5. Search and filtering # Search by name, username, domain, notes - performed locally, data isn\u0026rsquo;t sent to the server in plain text. Filters: by item type, by organization/collection, by tags.\n6. Folders # A personal logical structure, not tied to organizations. Data in a folder isn\u0026rsquo;t shared with other users, even if they\u0026rsquo;re in the same organization.\n7. Trash # Deleted entries don\u0026rsquo;t disappear immediately - they go to the trash, from where they can be restored or permanently deleted.\n8. Item context menu # View, Edit, Clone, Move to Folder/Collection, Add Favorite, Delete.\n9. Password Generator # Generates a password of the desired length and complexity (letters, digits, symbols, exclusion of similar-looking characters) - available directly from the Vault.\nBackups # A common question people ask online is how exactly to back up Vaultwarden. Here\u0026rsquo;s a minimal working approach.\nFor SQLite (the default database), it\u0026rsquo;s enough to copy the entire data directory while the container isn\u0026rsquo;t actively writing - or use sqlite3 .backup for a consistent snapshot without stopping the service:\n#!/usr/bin/env bash set -e SRC=\u0026#34;/path/to/docker/vaultwarden/data\u0026#34; DEST=\u0026#34;/backup/vaultwarden/$(date +%F)\u0026#34; mkdir -p \u0026#34;$DEST\u0026#34; sqlite3 \u0026#34;$SRC/db.sqlite3\u0026#34; \u0026#34;.backup \u0026#39;$DEST/db.sqlite3\u0026#39;\u0026#34; cp -r \u0026#34;$SRC/attachments\u0026#34; \u0026#34;$DEST/\u0026#34; 2\u0026gt;/dev/null || true cp -r \u0026#34;$SRC/sends\u0026#34; \u0026#34;$DEST/\u0026#34; 2\u0026gt;/dev/null || true cp \u0026#34;$SRC/rsa_key\u0026#34;* \u0026#34;$DEST/\u0026#34; 2\u0026gt;/dev/null || true # clean up backups older than 14 days find /backup/vaultwarden -maxdepth 1 -mtime +14 -exec rm -rf {} \\; Hook this up to cron (e.g., once a day) and make sure to verify that the backups actually restore - a \u0026ldquo;backup that\u0026rsquo;s never been restored,\u0026rdquo; as they say, is just a file taking up space.\nIf you use PostgreSQL/MySQL - use pg_dump/mysqldump respectively instead of copying the SQLite file.\nCommon mistakes # DOMAIN doesn\u0026rsquo;t match the real HTTPS address - this breaks email confirmation and TOTP/2FA. Check that the value exactly matches what the browser sees (including protocol, no trailing slash). WebSocket won\u0026rsquo;t connect - the reverse proxy isn\u0026rsquo;t proxying /notifications/hub with the Upgrade/Connection headers. Check the proxy config. SSO redirects to an error - the redirect URI in the OIDC provider\u0026rsquo;s settings doesn\u0026rsquo;t match Vaultwarden\u0026rsquo;s real address, or SSO_AUTHORITY doesn\u0026rsquo;t point to the provider\u0026rsquo;s/application\u0026rsquo;s root URL. No push notifications arriving - stale or incorrect PUSH_INSTALLATION_ID/PUSH_INSTALLATION_KEY, or the wrong relay region is selected (.com instead of .eu or vice versa). Warning about a plain-text ADMIN_TOKEN in the logs - the token isn\u0026rsquo;t hashed, see the section on vaultwarden hash --preset owasp. FAQ # Can Vaultwarden be used without a domain of my own? Technically yes (via IP), but the Web Vault requires a secure context (HTTPS) for the Web Crypto API, and without a domain it\u0026rsquo;s much harder to get a proper TLS certificate. In practice - the system won\u0026rsquo;t really work without a real domain.\nIs SSO mandatory? No, it\u0026rsquo;s an optional add-on. Regular registration with a master password works fine without it. Moreover, using SSO doesn\u0026rsquo;t disable the built-in authentication.\nCan I migrate data from Bitwarden Cloud? Yes - export the vault from Bitwarden Cloud (Settings → Export Vault) and import it into a freshly created account on Vaultwarden.\nWhat do I do if I forgot ADMIN_TOKEN? Generate a new one via vaultwarden hash --preset owasp and update .env/the environment variable, then restart the container. This has no effect on user data.\nSummary # Section / Item Purpose All Items All of the user\u0026rsquo;s entries Folders Personal categories Collections Shared categories (within organizations) Trash Trash bin Add Item Add a login / note / card Search Search across the Vault Password Generator Create strong passwords SSO Single sign-on via an external identity provider Push Instant push notifications on mobile clients Unfortunately, a single article can\u0026rsquo;t cover every capability of this excellent app, so for more details on all the settings, see the official Vaultwarden documentation.\n","date":"October 29, 2025","externalUrl":null,"permalink":"/en/posts/vaultwarden/","section":"Posts","summary":"A step-by-step guide to installing Vaultwarden - a lightweight self-hosted version of Bitwarden. From a basic docker-compose to an advanced configuration with SSO and push notifications.","title":"Vaultwarden — server installation, an alternative to Bitwarden","type":"posts"},{"content":"","date":"October 25, 2025","externalUrl":null,"permalink":"/en/tags/authelia/","section":"Tags","summary":"","title":"Authelia","type":"tags"},{"content":" Why you need Authentik at all (and what IAM / IdP means in a homelab / production) # Why solutions like Authentik / IAM / IdP are needed # In basic setups, each service (application, web interface, API) often implements its own form of login - its own users, password storage, session mechanism, and so on. This creates:\nDuplicated authentication/authorization logic Different passwords across different systems A larger security-error surface Difficulties with centralized user management, MFA, and auditing Problems with a unified session (SSO) across systems Solutions like IAM / IdP (Identity Provider) allow you to centralize authentication and authorization: services \u0026ldquo;delegate\u0026rdquo; the login process to the IdP solution, and the IdP issues a token/session/assertions that the services trust.\nBenefits in a production environment # Centralized security policy (MFA, IP restrictions, time-limited access) Unified auditing and logging Integration with LDAP, AD, and third-party OAuth providers Scalability: adding new services without duplicating authentication In a homelab / self-hosted environment # Control over your own data and passwords The ability to experiment with policies and customization Single sign-on for multiple home services (Nextcloud, Home Assistant, etc.) Levelling up your infrastructure to a production-grade level Bottom line: Authentik is one of the solutions that combines convenience, flexibility, and an open-source approach, making it suitable for both home labs and production.\nWhat Authentik is - a brief overview # Authentik is an open-source / open-core Identity Provider (IdP) and Single Sign-On (SSO) system, built with an emphasis on flexibility and extensibility.\nKey capabilities # Support for standards: OAuth2 / OIDC, SAML2, LDAP, SCIM, RADIUS A Flows / Stages mechanism for building authentication scenarios A convenient UI for admins and users Self-service (registration, password recovery, MFA) Conditional access policies API, Terraform, Blueprints - configuration as code Scaling from Docker to Kubernetes / Helm Support for external identity providers An IdP is a critically important security element. Authentik needs to be regularly updated and monitored. In 2024, vulnerabilities related to certificate management were reported, but they were promptly fixed.\nCore concepts # Concept Description Flows / Stages The logic of the authentication sequence (password, MFA, IP check, etc.). Applications / Providers Configuration of applications and login providers (OIDC, SAML, etc.). Policy / Conditions Access control based on attributes (group, IP, time of day). SCIM / LDAP / Federation Syncing users from external systems. Self-Service / Enrollment Interface for users (password change, MFA, etc.). Consent / Attribute Mapping Managing the attributes passed to applications. API / Automation Full automation of configuration via API, Terraform, Blueprints. Advantages and limitations # Advantages # High flexibility and customizability (flows, policies). Support for a wide range of protocols (OIDC, SAML, LDAP, RADIUS). Suits small/medium environments and Kubernetes clusters. Simpler interface compared to Keycloak. API and Terraform for automation. Open source - control over your data and code. Limitations # A smaller community than Keycloak\u0026rsquo;s. May require optimization under heavy load. Requires regular updates and auditing. Some features are available only in the enterprise version. Configuring flows requires experience. Comparing Authentik with competitors # Characteristic Authentik Keycloak Authelia Auth0 / Okta (SaaS) Solution type Self-host / open core Self-host / enterprise Self-host / gateway SaaS / managed Supported protocols OAuth2 / OIDC, SAML2, LDAP, SCIM, RADIUS OAuth2 / OIDC, SAML2, Kerberos, LDAP / AD SSO / 2FA, limited protocols OAuth2 / OIDC, SAML, social login Customization Very flexible (flows, policies) High (plugins) Simple Minimal Integrations LDAP, SCIM, external OAuth LDAP / AD, federation LDAP Many ready-made ones Installation Docker, Helm, UI Java stack (heavy) Lightweight No installation Scalability Medium loads, clustering Enterprise Small scenarios Unlimited Community Young, fast-growing Mature Niche Huge Security Requires updates Mature Simplified High (SLA) Cost Free / enterprise support Free / Red Hat support Free Subscription Best use case Homelab, SMB, customization Enterprise Simple SSO / 2FA No admin overhead Authentik is often called the \u0026ldquo;golden middle ground\u0026rdquo; between heavy IAM solutions and simple proxy systems like Authelia.\nA more detailed comparison of Authentik, Authelia, Keycloak, and ZITADEL against each other (by features, installation complexity, resource usage) is in a separate comparison article.\nInstallation and architectural recommendations # Installation approaches # Docker Compose - ideal for a homelab and testing Kubernetes / Helm - for production Cloud AMI / Marketplace - ready-made images (AWS, etc.) Architecture and tips # Separate the services: PostgreSQL, Redis, Authentik web/worker. Use external DB and Redis. Set up backups. Ensure TLS/HTTPS for the interfaces. Set up monitoring and updates. Use clustering and replication if needed. Minimal installation example (Docker Compose) version 2025.10.1 # Note Update note. At the time of publication, the current version was 2025.10.1, but Authentik releases often - as of August 2026, the current branch is 2026.5.x. Don\u0026rsquo;t blindly copy the version tag: before installing, check the releases page on GitHub and substitute the current AUTHENTIK_TAG. The overall structure of the docker-compose file hasn\u0026rsquo;t fundamentally changed since then.\n--- services: postgresql: image: docker.io/library/postgres:16-alpine container_name: authentik_postgres restart: unless-stopped healthcheck: interval: 30s retries: 5 start_period: 20s test: - CMD-SHELL - pg_isready -d $${POSTGRES_DB} -U $${POSTGRES_USER} timeout: 5s volumes: - database:/var/lib/postgresql/data environment: POSTGRES_PASSWORD: ${PG_PASS:?database password required} POSTGRES_USER: ${PG_USER:-authentik} POSTGRES_DB: ${PG_DB:-authentik} env_file: - .env networks: authentik: # server: command: server depends_on: postgresql: condition: service_healthy env_file: - .env image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.10.1} container_name: authentik_server restart: unless-stopped environment: AUTHENTIK_REDIS__HOST: redis AUTHENTIK_POSTGRESQL__HOST: postgresql AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} TZ: Europe/Moscow volumes: - ./media:/media - ./custom-templates:/templates networks: authentik: proxy: labels: - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.http.routers.authentik.entrypoints=web\u0026#34; - \u0026#34;traefik.http.routers.authentik.rule=Host(`authentik.domain.ru`)\u0026#34; - \u0026#34;traefik.http.middlewares.authentik-https-redirect.redirectscheme.scheme=https\u0026#34; - \u0026#34;traefik.http.routers.authentik.middlewares=authentik-https-redirect\u0026#34; - \u0026#34;traefik.http.routers.authentik-secure.entrypoints=websecure\u0026#34; ## Individual Application forwardAuth regex (catch any subdomain using individual application forwardAuth) - \u0026#34;traefik.http.routers.authentik-secure.rule=Host(`authentik.domain.ru`) || HostRegexp(`{subdomain:[a-z0-9]+}.domain.ru`) \u0026amp;\u0026amp; PathPrefix(`/outpost.goauthentik.io/`)\u0026#34; - \u0026#34;traefik.http.routers.authentik-secure.tls=true\u0026#34; - \u0026#34;traefik.http.routers.authentik-secure.service=authentik\u0026#34; - \u0026#34;traefik.http.services.authentik.loadbalancer.server.port=9000\u0026#34; - \u0026#34;traefik.docker.network=proxy\u0026#34; # worker: image: ${AUTHENTIK_IMAGE:-ghcr.io/goauthentik/server}:${AUTHENTIK_TAG:-2025.10.1} restart: unless-stopped command: worker container_name: authentik_worker environment: AUTHENTIK_REDIS__HOST: redis AUTHENTIK_POSTGRESQL__HOST: postgresql AUTHENTIK_POSTGRESQL__USER: ${PG_USER:-authentik} AUTHENTIK_POSTGRESQL__NAME: ${PG_DB:-authentik} AUTHENTIK_POSTGRESQL__PASSWORD: ${PG_PASS} TZ: Europe/Moscow # `user: root` and the docker socket volume are optional. # See more for the docker socket integration here: # https://goauthentik.io/docs/outposts/integrations/docker # Removing `user: root` also prevents the worker from fixing the permissions # on the mounted folders, so when removing this make sure the folders have the correct UID/GID # (1000:1000 by default) #user: root volumes: - /var/run/docker.sock:/var/run/docker.sock - ./media:/media - ./certs:/certs - ./custom-templates:/templates env_file: - .env depends_on: postgresql: condition: service_healthy networks: proxy: authentik: # volumes: database: driver: local # networks: proxy: external: true authentik: external: true PG_PASS=pass AUTHENTIK_SECRET_KEY=secret # SMTP Host Emails are sent to AUTHENTIK_ERROR_REPORTING__ENABLED=true AUTHENTIK_EMAIL__HOST=smtp.gmail.com AUTHENTIK_EMAIL__PORT=465 # Optionally authenticate (don\u0026#39;t add quotation marks to your password) AUTHENTIK_EMAIL__USERNAME=mail@gmail.com AUTHENTIK_EMAIL__PASSWORD=password # Use StartTLS AUTHENTIK_EMAIL__USE_TLS=false # Use SSL AUTHENTIK_EMAIL__USE_SSL=true AUTHENTIK_EMAIL__TIMEOUT=10 # Email address authentik will send from, should have a correct @domain AUTHENTIK_EMAIL__FROM=mail@gmail.com AUTHENTIK_ERROR_REPORTING__ENABLED=true ","date":"October 25, 2025","externalUrl":null,"permalink":"/en/posts/authentik-overview/","section":"Posts","summary":"A detailed overview of Authentik - an open-source system for centralized authentication and authorization (IdP/SSO). We’ll cover why IAM solutions are needed, the architecture, key features, and a comparison with alternatives.","title":"Authentik overview: architecture, features, and comparison with Keycloak","type":"posts"},{"content":"","date":"October 25, 2025","externalUrl":null,"permalink":"/en/tags/iam/","section":"Tags","summary":"","title":"IAM","type":"tags"},{"content":"A series of articles about modern authentication and authorization solutions: Authentik, Authelia, Keycloak, and Zitadel. We cover installation, configuration, reverse proxy integration, and compare approaches to SSO, MFA, and access management in home and corporate environments.\n","date":"October 25, 2025","externalUrl":null,"permalink":"/en/posts/single-sign-on/","section":"Posts","summary":"A series of articles about modern authentication and authorization solutions - Authentik, Authelia, Keycloak, and Zitadel. We cover installation, configuration, reverse proxy integration, and compare approaches to SSO, MFA, and access management in home and corporate environments.","title":"IAM and IdP Solutions","type":"posts"},{"content":"","date":"October 25, 2025","externalUrl":null,"permalink":"/en/series/iam-%D1%80%D0%B5%D1%88%D0%B5%D0%BD%D0%B8%D1%8F/","section":"Series","summary":"","title":"IAM-Решения","type":"series"},{"content":"","date":"October 25, 2025","externalUrl":null,"permalink":"/en/tags/idp/","section":"Tags","summary":"","title":"IdP","type":"tags"},{"content":"","date":"October 25, 2025","externalUrl":null,"permalink":"/en/tags/keycloak/","section":"Tags","summary":"","title":"Keycloak","type":"tags"},{"content":"","date":"October 25, 2025","externalUrl":null,"permalink":"/en/tags/mealie/","section":"Tags","summary":"","title":"Mealie","type":"tags"},{"content":" What is Mealie # Mealie is an open-source, self-hosted web app for managing recipes, planning meals, and building shopping lists.\nProject website: mealie.io\nDocumentation: docs.mealie.io\nKey features:\nInstall on your own server or home infrastructure - no dependency on cloud services. Import recipes from web pages using a built-in \u0026ldquo;scraper.\u0026rdquo; Modern Vue.js interface with a REST API backend. Meal planner and shopping lists. Support for multiple users and groups. Organize recipes into collections, tags, and categories. Main features of Mealie # Recipe import\nYou can enter recipes manually or paste a link to a web page, and Mealie will extract the ingredients and instructions.\nMore on GitHub: github.com/mealie-recipes/mealie\nRecipe editor\nFull editing of ingredients, instructions, photos, and descriptions.\nMeal planner\nDistribute meals across days of the week/month.\nShopping list\nAutomatically builds a list based on selected recipes, with the option to group items by store department.\nRecipe organization\nTags, categories, and collections (cookbooks) for easy searching.\nAPI and integrations\nREST API, webhooks, support for Home Assistant and other systems.\nLocalization\nThe interface is available in many languages.\nWhy Mealie is interesting for home enthusiasts # If you already have a home server or cluster (say, a Proxmox host and a mini PC), Mealie fits right in:\nRuns in a Docker or LXC container. Full control over your data - your recipes, meal plans, and shopping lists stay with you. Can be used as a content base for a blog or YouTube channel. Integrates with home automation: notifications about planned meals, ingredient lists on the fridge, and more. Possible limitations # Recipe scaling can be imperfect.\nDiscussion source on Reddit Requires basic self-hosting skills: setting up the server/container, backups, security. Mobile apps are third-party; the main way to use it is through the web interface.\nExample of an iOS mobile client What\u0026rsquo;s new in Mealie since the article was published # Note Update. This article was written for the Mealie version current as of October 2025. Since then several releases have come out (the current one as of August 2026 is v3.22.0), and the project has gained features that didn\u0026rsquo;t exist at the time of writing. I\u0026rsquo;ll cover the most notable ones and show how to use them.\nUnit standardization # Previously, a shopping list could duplicate the same ingredient with different units (for example, \u0026ldquo;1 pint of milk\u0026rdquo; and \u0026ldquo;2 cups of milk\u0026rdquo; from different recipes wouldn\u0026rsquo;t merge into one entry). Now units can be standardized, and Mealie automatically consolidates compatible quantities into a single shopping list entry. Standard units are configured on the Data Management page in the group settings - you can also add your own there.\nWarning A separate note for those used to cooking by grams and milliliters, as is mostly the norm in Russia. Standardization in Mealie merges compatible units of the same type (volume to volume: pint → cups, weight to weight: oz → lb), but it can\u0026rsquo;t reliably convert volume to weight - meaning \u0026ldquo;1 cup of flour\u0026rdquo; won\u0026rsquo;t turn into correct grams on its own, because that requires the density of the specific product, which simply isn\u0026rsquo;t in Mealie\u0026rsquo;s database. Most recipes imported from English-language sites use cups, ounces, and Fahrenheit - when importing such a recipe, it\u0026rsquo;s worth manually checking and, if needed, converting to grams/milliliters/Celsius yourself, since the automation won\u0026rsquo;t always save you here.\nA more reliable web scraper # The recipe parser for regular websites has been noticeably improved - many sites where importing used to break (forcing you to manually copy the page\u0026rsquo;s HTML) can now be imported again with just a link.\nAnnouncements - developer announcements # A separate announcements channel from the project maintainers has appeared in the interface - it carries important news about features that require user action, in addition to the regular release notes.\nAI features in Mealie # This is arguably the most substantial addition to Mealie recently, so I\u0026rsquo;ll cover it separately and in detail.\nWhich providers are supported # An important point for the homelab audience: Mealie isn\u0026rsquo;t locked to OpenAI. It works with any OpenAI-compatible API, namely:\nOpenAI - the simplest option, but paid (by tokens and by audio minutes for Whisper); Azure OpenAI - if you have a corporate Azure subscription; Ollama - a self-hosted option you can run on the same Proxmox host or mini PC and pay nothing at all, at the cost of recognition quality depending on the local model chosen; any other custom endpoint implementing an OpenAI-compatible API. For those who fundamentally don\u0026rsquo;t want to send their recipes and videos to some external service - Ollama looks like the most logical choice specifically for a homelab: privacy is preserved, and no money is needed.\nWhat exactly the AI can do in Mealie # Import with AI - the main feature. Lets you create a recipe from plain text, HTML, JSON (including schema.org/Recipe markup), a photo of a recipe (printed or even handwritten), or a link to a video (YouTube, TikTok, Instagram) - in the latter case the audio track is transcribed via a Whisper-compatible model and turned into text, from which a structured recipe is then assembled. There\u0026rsquo;s also an optional translation of the result into your desired language. Fallback parser for site scraping - if the regular scraper fails to parse a page (unusual layout, JS rendering, etc.), the AI kicks in as a fallback and tries to extract the recipe directly from the page content. AI ingredient parser - an alternative to the built-in NLP and brute-force parsers when breaking down an ingredient list into quantity/unit/product. Automatic tag, category, and tool matching - the AI suggests suitable tags and categories for a new recipe based on its content. How to set it up # Everything is configured in Group Settings, not globally for the whole server - this is convenient if Mealie is used by several families/groups with different providers.\nSpecify a default provider (Default provider) - without this step no AI feature will work, the buttons simply stay hidden. If you want to recognize photos of recipes, the provider must support working with images (for OpenAI that\u0026rsquo;s models like gpt-4o/gpt-5, for Ollama - vision models like llava). If you want to import recipes from video, you need a separate audio provider, e.g. whisper-1. The key and endpoint address can be set either via environment variables in docker-compose.yml (OPENAI_API_KEY - see the example compose file above), or directly in the interface via Group Settings - the second way is more convenient if different groups need different providers. Example for Ollama: for base_url you specify something like http://ollama:11434/v1 (the address of your Ollama container/host), and the API key field can be filled with any value - Ollama simply ignores it, but the field is required to fill out in Mealie\u0026rsquo;s form.\nNote If you use OpenAI, the free tier won\u0026rsquo;t be enough for these features - you need at least one payment (usually $5 is enough), after which the account moves to Tier 1 with limits sufficient for home use.\nAll the AI features listed are optional add-ons. Without a single configured provider, Mealie continues to work exactly as it always did, completely free and without AI (regular link scraping, manual recipe entry) - nothing in the base functionality breaks.\nHow to start using Mealie # Prepare a server or container (Docker Compose or LXC in Proxmox). Install Mealie: pull the Docker image, configure the database and environment variables. Connect via browser and create a user. Import a few recipes (links, manually, and, with an OpenAI key configured, also from video or photo). Create a meal plan for the week and check the shopping list. Set up backups. (Optional) Integrate with Home Assistant for meal notifications. Mealie is a great tool for home cooks and those who value full control over their data.\nIf you have a Proxmox server or cluster, getting it running is a matter of minutes.\nSample docker compose file used in the video # --- services: mealie: image: ghcr.io/mealie-recipes/mealie:v3.22.0 # do not use :latest - pin an explicit version, check the current one at https://github.com/mealie-recipes/mealie/releases container_name: mealie #ports: # - \u0026#34;9925:9000\u0026#34; # deploy: resources: limits: memory: 1000M # volumes: - /home/user/docker/mealie/mealie-data:/app/data/ environment: # Set Backend ENV Variables Here - ALLOW_SIGNUP=false - PUID=1000 - PGID=1000 - TZ=Europe/Moscow - MAX_WORKERS=1 - WEB_CONCURRENCY=1 - BASE_URL=https://mealie.user.ru - DEFAULT_GROUP=Home - DEFAULT_HOUSEHOLD=Family #AI features (recipe import from video, photo recognition, etc.) - optional # - OPENAI_API_KEY=sk-... #Email Configuration - SMTP_HOST=smtp.gmail.com - SMTP_PORT=465 - SMTP_FROM_NAME=mail@gmail.com - SMTP_AUTH_STRATEGY=SSL # Options: \u0026#39;TLS\u0026#39;, \u0026#39;SSL\u0026#39;, \u0026#39;NONE\u0026#39; - SMTP_FROM_EMAIL=mail@gmail.com - SMTP_USER=mail@gmail.com - SMTP_PASSWORD=app_password #OIDC credentials - OIDC_AUTH_ENABLED=true - OIDC_SIGNUP_ENABLED=true - OIDC_CONFIGURATION_URL=https://authentik.domain.ru/application/o/mealie/.well-known/openid-configuration - OIDC_CLIENT_ID=secret - OIDC_CLIENT_SECRET=big secret - OIDC_REMEMBER_ME=true # - OIDC_AUTO_REDIRECT=false # - OIDC_USER_CLAIM=email # - OIDC_GROUPS_CLAIM=groups # - OIDC_USER_GROUP=my_family # - OIDC_ADMIN_GROUP=mealie_Admins # - OIDC_USER_GROUP=mealie_users # - OIDC_PROVIDER_NAME=Authentik # - LOG_LEVEL=DEBUG restart: unless-stopped networks: proxy: security_opt: - no-new-privileges:true labels: - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.http.routers.mealie.entrypoints=web\u0026#34; - \u0026#34;traefik.http.routers.mealie.rule=Host(`mealie.domain.ru`)\u0026#34; - \u0026#34;traefik.http.middlewares.mealie-https-redirect.redirectscheme.scheme=https\u0026#34; - \u0026#34;traefik.http.routers.mealie.middlewares=mealie-https-redirect\u0026#34; - \u0026#34;traefik.http.routers.mealie-secure.entrypoints=websecure\u0026#34; - \u0026#34;traefik.http.routers.mealie-secure.rule=Host(`mealie.domain.ru`)\u0026#34; - \u0026#34;traefik.http.routers.mealie-secure.tls=true\u0026#34; - \u0026#34;traefik.http.routers.mealie-secure.service=mealie\u0026#34; - \u0026#34;traefik.http.services.mealie.loadbalancer.server.port=9000\u0026#34; - \u0026#34;traefik.docker.network=proxy\u0026#34; networks: proxy: external: true ","date":"October 25, 2025","externalUrl":null,"permalink":"/en/posts/mealie/","section":"Posts","summary":"A step-by-step guide to installing and configuring Mealie for managing recipes on your own server. Covers installation via Docker, database setup, the web interface and mobile access, integration with external recipe sources, plus the new AI features (importing recipes from video) and unit standardization.","title":"Mealie - self-hosted app for recipes, meal planning, and shopping lists","type":"posts"},{"content":"","date":"25 October 2025","externalUrl":null,"permalink":"/categories/nextcloud/","section":"Categories","summary":"","title":"Nextcloud","type":"categories"},{"content":"","date":"25 October 2025","externalUrl":null,"permalink":"/series/nextcloud/","section":"Series","summary":"","title":"Nextcloud","type":"series"},{"content":"","date":"25 October 2025","externalUrl":null,"permalink":"/tags/nextcloud/","section":"Tags","summary":"","title":"Nextcloud","type":"tags"},{"content":" Установка полноценного Nextcloud в LXC контейнер в Proxmox # Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nВ этом видео я покажу, как с нуля установить Nextcloud - без Docker, на полноценный стек Apache, MariaDB и PHP. Безопасно и стабильно, стильно и молодежно. Вариант, который я покажу сегодня, выдержит нагрузки даже малосреднего офиса, не говоря уже про домашнее использование.\nНо прежде всего я хотел бы поблагодарить своих спонсоров на бусти. Ребята, огромное, большое вам спасибо за то что помогаете развитию этого канала. Канал живет исключительно с вашей помощью. А Ваша помощь идет исключительно на развитие этого канала. Ну а те кто не в курсе, на бусти, для спонсоров, я выкладываю ролики раньше, до месяца раньше, чем они появляются в открытом доступе, поэтому: если вам нравится контент, который выходит на этом канале; вы хотите поддержать развитие этого канала; может быть вы просто хотите посмотреть что-то пораньше, то ссылка на бусти и все остальные контакты, телеграмм, запасные каналы на отечественных площадках, будут в описании.\nУ меня на youtube - канале уже есть два ролика, посвященных непосредственно особенностям установки Nextcloud AIO и Nextcloud в докере. В том числе есть ролики про установку и связку OnlyOffice с Nextcloud, а также галереи Memories. Этот ролик будет финальным в серии. Но это не точно.\nСсылки на другие варианты установки # В этом ролике установим полноценный Nextcloud, но с определенными особенностями. Однако сначала, по законам жанра, я должен рассказать неофитам, что такое Nextcloud. Nextcloud - это облачный сервис с открытым исходным кодом, который позволяет хранить, синхронизировать и совместно использовать файлы, а также расширять функциональность за счёт встроенных приложений: календарей, видеозвонков, заметок, редакторов документов и т.д. Поэтому когда вы слышите, что Nextcloud замена коммерческим облачным хранилищам, посмотрите на этого человека снисходительно, мол, молодой ты ищо, ничего не понимаешь, салага. Некстклауд давно перешел тут границу нормальности, когда это было просто облачное хранилище. Сейчас это конкурент таким решениям, как Google Workspace и аналоги.\nТеперь поговорим об особенностях сегодняшней установки. Официальных сборок Некстклауда всего две. Это то, что мы установим сегодня и Nextcloud AIO (там, по-моему, вообще один человек все собирает). Всё остальное - это заслуга коммюнити. В роликах про установку полноценного Nextcloud вы обычно видите, как люди ставят все в ВМ, устанавливают туда потом certbot, устанавливают nginx или ngrok, выпускают ssl сертификат. Все это мы делать не будем. Почему? У нас есть свой обратный прокси и пользоваться мы будем именно им. Устанавливать мы все будем в LXC контейнер. Сейчас суровые админы должны закричать на меня, мол, что ты делаешь, так нельзя. Нельзя. В продакшене нельзя. Дома можно. Почему LXC? Потому что мы туда можем прокинуть встроенное в процессор видеоядро, и при этом еще можно будет это же видеоядро использовать и в других контейнерах. Как прокидывается видеоядро, смотрите ролик у меня на канале.\nУ меня уже создан lxc контейнер, и обратный прокси настроен на выпуск сертификата на айпи, по которому находится наш контейнер, и порт 80. Я предполагаю, что вы знаете, как настраивать конкретно ваш обратный прокси. На этом вступление закончилось.\nПоехали.\nШаг 1: Обновляем систему # Обновляем пакеты и настраиваем кодировку: sudo su apt update \u0026amp;\u0026amp; apt upgrade -y dpkg-reconfigure locales Шаг 2: Устанавливаем Apache2 и PHP Modules # Устанавливаем Apache2: apt install apache2 -y Устанавливаем зависимости: apt install php php-common libapache2-mod-php php-bz2 php-gd php-mysql php-curl php-mbstring php-imagick php-zip php-common php-curl php-xml php-json php-bcmath php-xml php-intl php-gmp zip unzip wget smbclient libmagickcore-6.q16-7-extra ffmpeg intel-media-va-driver-non-free ffmpeg va-driver-all ocl-icd-libopencl1 intel-opencl-icd vainfo intel-gpu-tools -y Активируем необходимые модули Apache: a2enmod env rewrite dir mime headers setenvif ssl Перезапускаем, включаем и проверяем работоспособность Apache. systemctl restart apache2 systemctl enable apache2 systemctl status apache2 Проверяем загрузку модулей Apache: apache2ctl -M Шаг 3: Устанавливаем и конфигурируем MariaDB сервер # Устанавливаем пакет mariadb-server: apt install mariadb-server -y Заходим в MariaDB: mysql Создаем базу данных и пользователя для Nextcloud и задаем необходимые разрешения пользователю: CREATE USER \u0026#39;ncloud\u0026#39;@\u0026#39;localhost\u0026#39; IDENTIFIED BY \u0026#39;admin123\u0026#39;; CREATE DATABASE ncloud CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; GRANT ALL PRIVILEGES ON ncloud.* TO \u0026#39;ncloud\u0026#39;@\u0026#39;localhost\u0026#39;; FLUSH PRIVILEGES; quit; Перезапускаем и активируем MariaDB: systemctl restart mariadb systemctl enable mariadb Проверяем, что MariaDB запущенна: systemctl status mariadb Шаг 4: Загружаем, разархивируем и задаем разрешения Nextcloud # Загружаем и разархивируем в папку /var/www/html: cd /var/www/html wget https://download.nextcloud.com/server/releases/latest.zip unzip latest.zip Удалем ненужный архив: rm -rf latest.zip Задаем права на папку: chown -R www-data:www-data /var/www/html/nextcloud/ Шаг 5: Устанавливаем Nextcloud из командной строки # Запускаем приведенную ниже команду для инсталляции nextcloud (нужно внести свои данные конечно) cd /var/www/html/nextcloud sudo -E -u www-data php occ maintenance:install --database \\ \u0026#34;mysql\u0026#34; --database-name \u0026#34;ncloud\u0026#34; --database-user \u0026#34;ncloud\u0026#34; --database-pass \\ \u0026#39;admin123\u0026#39; --admin-user \u0026#34;admin\u0026#34; --admin-pass \u0026#34;password\u0026#34; Nextcloud разрешает доступ только с локального хоста, это может привести к ошибке «Доступ через недоверенный домен». Нам нужно разрешить доступ к Nextcloud, используя IP-адрес или доменное имя sudo nano /var/www/html/nextcloud/config/config.php \u0026#39;trusted_domains\u0026#39; =\u0026gt; array ( 0 =\u0026gt; \u0026#39;localhost\u0026#39;, 1 =\u0026gt; \u0026#39;nextcloud.your_domain.ru\u0026#39;, // we Included the Sub Domain ), \u0026#39;overwritehost\u0026#39; =\u0026gt; \u0026#39;nextcloud.your_domain.ru\u0026#39;, \u0026#39;overwriteprotocol\u0026#39; =\u0026gt; \u0026#39;https\u0026#39;, \u0026#39;overwrite.cli.url\u0026#39; =\u0026gt; \u0026#39;https://nextcloud.your_domain.ru\u0026#39;, \u0026#39;trusted_proxies\u0026#39; =\u0026gt; array ( 0 =\u0026gt; \u0026#39;192.168.0.0/16\u0026#39;, 1 =\u0026gt; \u0026#39;172.16.0.0/12\u0026#39;, 2 =\u0026gt; \u0026#39;10.0.0.0/8\u0026#39;, 3 =\u0026gt; \u0026#39;fc00::/7\u0026#39;, 4 =\u0026gt; \u0026#39;fe80::/10\u0026#39;, 5 =\u0026gt; \u0026#39;2001:db8::/32\u0026#39;, ), \u0026#39;default_phone_region\u0026#39; =\u0026gt; \u0026#39;RU\u0026#39;, \u0026#39;allow_local_remote_servers\u0026#39; =\u0026gt; true, Настройте Apache для загрузки Nextcloud из папки /var/www/html/nextcloud: nano /etc/apache2/sites-enabled/000-default.conf \u0026lt;VirtualHost *:80\u0026gt; ServerAdmin webmaster@localhost DocumentRoot /var/www/html/nextcloud \u0026lt;Directory /var/www/html/nextcloud\u0026gt; Options Indexes FollowSymLinks AllowOverride All Require all granted \u0026lt;/Directory\u0026gt; ServerName nextcloud.your_domain.ru \u0026lt;IfModule mod_headers.c\u0026gt; Header always set Strict-Transport-Security \u0026#34;max-age=15552000; includeSubDomains\u0026#34; \u0026lt;/IfModule\u0026gt; ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined \u0026lt;/VirtualHost\u0026gt; Перезапускаем Apache: systemctl restart apache2 Теперь перейдите в браузер и введите http://[ip или полное доменное имя] сервера. Появится страница входа в Nextcloud, показанная ниже. Шаг 6: Установка и настройка PHP-FPM с Apache # Установка PHP-FPM (ниже везде используется PHP 8.3 - проверьте актуальную поддерживаемую версию перед установкой, на данный момент Nextcloud поддерживает PHP 8.2-8.5): apt install php8.3-fpm Проверьте, запущен ли PHP-FPM, его версию и создан ли сокет: service php8.3-fpm status php-fpm8.3 -v ls -la /var/run/php/php8.3-fpm.sock Отключите mod_php и модуль prefork: a2dismod php8.3 a2dismod mpm_prefork Активируйте PHP-FPM: a2enmod mpm_event proxy_fcgi setenvif a2enconf php8.3-fpm Перезапустите Apache, чтобы перезагрузить все модули и конфигурации: systemctl restart apache2 Теперь, чтобы настроить размер загружаемого файла и производительность, нам нужно изменить некоторые параметры php.ini, перечисленные ниже в файле /etc/php/8.3/fpm/php.ini. Вы можете задать собственные значения в зависимости от вашей среды.\nupload_max_filesize = 64M post_max_size = 96M memory_limit = 512M max_execution_time = 600 max_input_vars = 3000 max_input_time = 1000 Проверьте текущее значение: grep -E \u0026#34;upload_max_filesize|post_max_size|memory_limit|max_execution_time|max_input_vars|max_input_time\u0026#34; /etc/php/8.3/fpm/php.ini Вместо ручного внесения изменений вы можете выполнить следующую команду для немедленного внесения изменений. Это сэкономит время. sed -i \u0026#39;s/^upload_max_filesize.*/upload_max_filesize = 64M/; s/^post_max_size.*/post_max_size = 96M/; s/^memory_limit.*/memory_limit = 512M/; s/^max_execution_time.*/max_execution_time = 600/; s/^;max_input_vars.*/max_input_vars = 3000/; s/^max_input_time.*/max_input_time = 1000/\u0026#39; /etc/php/8.3/fpm/php.ini или\nsed -i \u0026#39;s/^upload_max_filesize.*/upload_max_filesize = 16G/; s/^post_max_size.*/post_max_size = 16G/; s/^memory_limit.*/memory_limit = 2048M/; s/^max_execution_time.*/max_execution_time = 3600/; s/^;max_input_vars.*/max_input_vars = 3600/; s/^max_input_time.*/max_input_time = 3600/\u0026#39; /etc/php/8.3/fpm/php.ini Теперь нам нужно обновить конфигурации пула PHP-FPM в /etc/php/8.3/fpm/pool.d/ www.conf. Ниже приведены некоторые оптимальные значения, но вам следует задать свои собственные значения.\npm.max_children = 64 pm.start_servers = 16 pm.min_spare_servers = 16 pm.max_spare_servers = 32 Проверим текущии значения: grep -E \u0026#34;pm.max_children|pm.start_servers|pm.min_spare_servers|pm.max_spare_servers\u0026#34; /etc/php/8.3/fpm/pool.d/www.conf Измените все значения одновременно с помощью следующей команды: sed -i \u0026#39;s/^pm.max_children = .*/pm.max_children = 64/; s/^pm.start_servers = .*/pm.start_servers = 16/; s/^pm.min_spare_servers = .*/pm.min_spare_servers = 16/; s/^pm.max_spare_servers = .*/pm.max_spare_servers = 32/\u0026#39; /etc/php/8.3/fpm/pool.d/www.conf или\nsed -i \u0026#39;s/^pm.max_children = .*/pm.max_children = 70/; s/^pm.start_servers = .*/pm.start_servers = 20/; s/^pm.min_spare_servers = .*/pm.min_spare_servers = 20/; s/^pm.max_spare_servers = .*/pm.max_spare_servers = 60/\u0026#39; /etc/php/8.3/fpm/pool.d/www.conf Теперь перезапустите PHP-FPM, чтобы применить все изменения: service php8.3-fpm restart Теперь вставьте приведенный ниже код в файл конфигурации сайта Apache по умолчанию /etc/apache2/sites-enabled/000-default.conf, он укажет Apache передать обработку PHP-файла PHP-FPM.\n\u0026lt;FilesMatch \u0026#34;.php$\u0026#34;\u0026gt; SetHandler \u0026#34;proxy:unix:/var/run/php/php8.3-fpm.sock|fcgi://localhost/\u0026#34; \u0026lt;/FilesMatch\u0026gt; После предоставления кода конфигурация сайта Apache по умолчанию будет выглядеть так, как показано ниже: nano /etc/apache2/sites-enabled/000-default.conf \u0026lt;VirtualHost *:80\u0026gt; # The ServerName directive sets the request scheme, hostname and port that # the server uses to identify itself. This is used when creating # redirection URLs. In the context of virtual hosts, the ServerName # specifies what hostname must appear in the request\u0026#39;s Host: header to # match this virtual host. For the default virtual host (this file) this # value is not decisive as it is used as a last resort host regardless. # However, you must set it for any further virtual host explicitly. #ServerName www.example.com ServerAdmin webmaster@localhost DocumentRoot /var/www/html/nextcloud \u0026lt;Directory /var/www/html/nextcloud\u0026gt; Options Indexes FollowSymLinks AllowOverride All Require all granted \u0026lt;/Directory\u0026gt; \u0026lt;FilesMatch \u0026#34;.php$\u0026#34;\u0026gt; SetHandler \u0026#34;proxy:unix:/var/run/php/php8.3-fpm.sock|fcgi://localhost/\u0026#34; \u0026lt;/FilesMatch\u0026gt; ServerName nextcloud.your_domain.ru \u0026lt;IfModule mod_headers.c\u0026gt; Header always set Strict-Transport-Security \u0026#34;max-age=15552000; includeSubDomains\u0026#34; \u0026lt;/IfModule\u0026gt; # Available loglevels: trace8, ..., trace1, debug, info, notice, warn, # error, crit, alert, emerg. # It is also possible to configure the loglevel for particular # modules, e.g. #LogLevel info ssl:warn ErrorLog ${APACHE_LOG_DIR}/error.log CustomLog ${APACHE_LOG_DIR}/access.log combined # For most configuration files from conf-available/, which are # enabled or disabled at a global level, it is possible to # include a line for only one particular virtual host. For example the # following line enables the CGI configuration for this host only # after it has been globally disabled with \u0026#34;a2disconf\u0026#34;. #Include conf-available/serve-cgi-bin.conf \u0026lt;/VirtualHost\u0026gt; Теперь перезапустите Apache, чтобы изменения вступили в силу: systemctl restart apache2 Шаг 7: Создайте страницу info.php для проверки функций PHP (опционально. После завершения проверки, файл надо удалить) # Создайте страницу info.php, она покажет нам, включены ли PHP-FPM, OPCache, APCu в PHP.\ncd /var/www/html/nextcloud nano info.php \u0026lt;?php phpinfo(); ?\u0026gt; Теперь перейдите по адресу [URL]/info.php. Если PHP-FPM включён в PHP, будет показано «Server API FPM/FastCGI».\nШаг 8: Включите OPCache в PHP # Включите OPCache в PHP: Проверьте, запущен ли он, с помощью файла [URL]/info.php, который мы создали ранее. JIT-компиляция (Just-In-Time) Opcache - важная функция. JIT-компиляция повышает производительность PHP, компилируя код в машинный язык во время выполнения, а не интерпретируя его при каждом запуске. Это может значительно повысить производительность ресурсоёмких задач. Поэтому её включение будет очень эффективным для повышения производительности Nextcloud.\nnano /etc/php/8.3/fpm/conf.d/10-opcache.ini zend_extension=opcache.so opcache.enable=1 opcache.enable_cli=1 opcache.interned_strings_buffer=64 opcache.max_accelerated_files=12000 opcache.memory_consumption=512 opcache.save_comments=1 opcache.revalidate_freq=60 opcache.jit = 1255 opcache.jit_buffer_size = 256M Перезапустите PHP-FPM, чтобы изменения вступили в силу: service php8.3-fpm restart Шаг 9: Включите APCu в PHP # Включить APCu в PHP: apt install php8.3-apcu nano /etc/php/8.3/fpm/conf.d/20-apcu.ini extension=apcu.so apc.enable_cli=1 Теперь перезапустите PHP-FPM и Apache.\nsystemctl restart php8.3-fpm systemctl restart apache2 Теперь проверьте [URL]/info.php еще раз, он покажет «Поддержка APCu включена» (“APCu support Enabled”).\nНастройте Nextcloud на использование APCu для кэширования памяти: nano /var/www/html/nextcloud/config/config.php \u0026#39;memcache.local\u0026#39; =\u0026gt; \u0026#39;\\OC\\Memcache\\APCu\u0026#39;, Шаг 10: Установка и настройка Redis Cache # Установка и настройка Redis Cache В Nextcloud Redis используется для локального и распределенного кэширования, а также для транзакционной блокировки файлов. Для локального кэширования мы использовали APCu, который быстрее Redis. Redis будет использоваться для блокировки файлов. Механизм транзакционной блокировки файлов Nextcloud блокирует файлы, предотвращая их повреждение во время нормальной работы.\nУстановите Redis Server и расширение Redis php\napt install redis-server php-redis -y Запустите и включите службу Redis. systemctl start redis-server systemctl enable redis-server systemctl status redis-server Настройте Redis для использования Unix Socket вместо портов nano /etc/redis/redis.conf port 0 unixsocket /var/run/redis/redis.sock unixsocketperm 770 Добавьте пользователя Apache в группу Redis usermod -a -G redis www-data Настройте Nextcloud для использования Redis для блокировки файлов nano /var/www/html/nextcloud/config/config.php \u0026#39;filelocking.enabled\u0026#39; =\u0026gt; \u0026#39;true\u0026#39;, \u0026#39;memcache.distributed\u0026#39; =\u0026gt; \u0026#39;\\\\OC\\\\Memcache\\\\Redis\u0026#39;, \u0026#39;memcache.locking\u0026#39; =\u0026gt; \u0026#39;\\\\OC\\\\Memcache\\\\Redis\u0026#39;, \u0026#39;redis\u0026#39; =\u0026gt; [ \u0026#39;host\u0026#39; =\u0026gt; \u0026#39;/var/run/redis/redis.sock\u0026#39;, \u0026#39;port\u0026#39; =\u0026gt; 0, \u0026#39;dbindex\u0026#39; =\u0026gt; 0, \u0026#39;password\u0026#39; =\u0026gt; \u0026#39;\u0026#39;, \u0026#39;timeout\u0026#39; =\u0026gt; 1.5, ], Включите блокировку сеанса Redis в PHP nano /etc/php/8.3/fpm/php.ini redis.session.locking_enabled=1 redis.session.lock_retries=-1 redis.session.lock_wait_time=10000 Перезапустите Redis, PHP-FPM и Apache systemctl restart redis-server systemctl restart php8.3-fpm systemctl restart apache2 Вы можете проверить, включены ли функции в PHP nextcloud-ubuntu-24.04-redis Redis is Installed for Nextcloud https://help.nextcloud.com/t/installing-redis-for-memcache/162599/6\nЯ предполагаю, что вы используете traefik в качестве обратного прокси-сервера, и вам не нужен certbot. Поэтому мы добавили соответствующие значения в /etc/apache2/sites-enabled/000-default.conf.\nВключаем Pretty URL’s:\nnano /var/www/html/nextcloud/config/config.php \u0026#39;htaccess.RewriteBase\u0026#39; =\u0026gt; \u0026#39;/\u0026#39;, Эта команда обновит файл .htaccess для переадресации\nsudo -E -u www-data php -d apc.enable_cli=1 /var/www/html/nextcloud/occ maintenance:update:htaccess Другие необходимые команды sudo -E -u www-data php /var/www/html/nextcloud/occ maintenance:repair --include-expensive sudo -E -u www-data php /var/www/html/nextcloud/occ db:add-missing-indices sudo -E -u www-data php /var/www/html/nextcloud/occ config:system:set maintenance_window_start --type=integer --value=1 sudo crontab -u www-data -e */5 * * * * php -f /var/www/html/nextcloud/cron.php sudo -E -u www-data php /var/www/html/nextcloud/occ files:scan --all sudo -E -u www-data php /var/www/html/nextcloud/occ app:update --all ","date":"25 October 2025","externalUrl":null,"permalink":"/posts/nextcloud-in-lxc/","section":"Posts","summary":"Подробная инструкция по установке и настройке Nextcloud внутри LXC-контейнера. Рассмотрены шаги по развертыванию, настройке пользователей, хранилища и веб-интерфейса, чтобы безопасно и эффективно управлять личным облачным сервером.","title":"Nextcloud в Proxmox: Полная установка в LXC без Docker","type":"posts"},{"content":"","date":"October 25, 2025","externalUrl":null,"permalink":"/en/categories/recipes/","section":"Categories","summary":"","title":"Recipes","type":"categories"},{"content":"","date":"October 25, 2025","externalUrl":null,"permalink":"/en/tags/zitadel/","section":"Tags","summary":"","title":"Zitadel","type":"tags"},{"content":" Что такое Nextcloud # Nextcloud - популярная open-source платформа для создания собственного облачного хранилища и совместной работы.\nОна позволяет хранить файлы, документы, фотографии, синхронизировать их между устройствами, а также использовать встроенные сервисы:\nкалендарь и задачи; видеоконференции (Nextcloud Talk); офисные документы (Nextcloud Office / Collabora); систему заметок и совместного редактирования. Nextcloud часто называют самостоятельной альтернативой Google Workspace и Microsoft 365, которую можно полностью контролировать и размещать на своём сервере без зависимости от внешних облаков.\nЧто такое Nextcloud AIO # Nextcloud AIO (All-in-One) - официальная сборка Nextcloud, созданная разработчиками проекта для максимального упрощения установки и обновления.\nВ отличие от классической установки, где приходится вручную настраивать Apache/Nginx, PHP, Redis, MariaDB и Cron, AIO использует Docker и включает всё необходимое в контейнерах:\nNextcloud (веб-интерфейс); PostgreSQL (база данных); Redis (кеширование); Collabora Online (редактирование документов); OnlyOffice (опционально); Backup-контейнер (автоматическое резервное копирование). Главное преимущество AIO - автоматическое обновление всех компонентов и возможность развернуть рабочее облако всего за несколько минут.\nСборка идеально подходит для домашних серверов, LXC-контейнеров в Proxmox или VPS, где важны простота и стабильность.\nКогда стоит использовать Nextcloud AIO? # Если вы хотите быстро развернуть Nextcloud с минимальными усилиями и без необходимости настройки отдельных компонентов.\nТребования к установке # Перед началом убедитесь, что у вас установлены:\nDocker и Docker Compose (версии 2.0+); сервер с не менее чем 2 ГБ ОЗУ; доменное имя и доступ по HTTPS (желательно через Traefik, Caddy или Nginx Proxy Manager). Docker Compose для Nextcloud AIO # Ниже приведён минимальный пример docker-compose.yml для запуска Nextcloud AIO с обратным прокси Traefik, как показано в ролике в начале статьи:\nservices: nextcloud-aio-mastercontainer: image: ghcr.io/nextcloud-releases/all-in-one:v13.3.1 # Официальный образ переехал с Docker Hub (nextcloud/all-in-one) на ghcr.io из-за новых ограничений на скачивание с Docker Hub - если найдёте старую ссылку на nextcloud/all-in-one, она устарела. Версию лучше зафиксировать и сверять с актуальной на https://github.com/nextcloud/all-in-one/releases, а не брать latest init: true restart: always container_name: nextcloud-aio-mastercontainer # This line is not allowed to be changed as otherwise AIO will not work correctly volumes: - nextcloud_aio_mastercontainer:/mnt/docker-aio-config # This line is not allowed to be changed as otherwise the built-in backup solution will not work - /var/run/docker.sock:/var/run/docker.sock:ro # May be changed on macOS, Windows or docker rootless. See the applicable documentation. If adjusting, don\u0026#39;t forget to also set \u0026#39;WATCHTOWER_DOCKER_SOCKET_PATH\u0026#39;! #network_mode: bridge # add to the same network as docker run would do ports: #- 80:80 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md - 8087:8080 #- 8443:8443 # Can be removed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md environment: # Is needed when using any of the options below AIO_DISABLE_BACKUP_SECTION: false # Setting this to true allows to hide the backup section in the AIO interface. See https://github.com/nextcloud/all-in-one#how-to-disable-the-backup-section APACHE_PORT: 11000 # Is needed when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else). See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md APACHE_IP_BINDING: 0.0.0.0 # Should be set when running behind a web server or reverse proxy (like Apache, Nginx, Caddy, Cloudflare Tunnel and else) that is running on the same host. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md BORG_RETENTION_POLICY: --keep-within=7d --keep-weekly=4 --keep-monthly=6 # Allows to adjust borgs retention policy. See https://github.com/nextcloud/all-in-one#how-to-adjust-borgs-retention-policy # COLLABORA_SECCOMP_DISABLED: false # Setting this to true allows to disable Collabora\u0026#39;s Seccomp feature. See https://github.com/nextcloud/all-in-one#how-to-disable-collaboras-seccomp-feature NEXTCLOUD_DATADIR: /media/nextcloud # Allows to set the host directory for Nextcloud\u0026#39;s datadir. ⚠️⚠️⚠️ Warning: do not set or adjust this value after the initial Nextcloud installation is done! See https://github.com/nextcloud/all-in-one#how-to-change-the-default-location-of-nextclouds-datadir NEXTCLOUD_MOUNT: /media # Allows the Nextcloud container to access the chosen directory on the host. See https://github.com/nextcloud/all-in-one#how-to-allow-the-nextcloud-container-to-access-directories-on-the-host # NEXTCLOUD_UPLOAD_LIMIT: 10G # Can be adjusted if you need more. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-upload-limit-for-nextcloud # NEXTCLOUD_MAX_TIME: 3600 # Can be adjusted if you need more. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-max-execution-time-for-nextcloud # NEXTCLOUD_MEMORY_LIMIT: 512M # Can be adjusted if you need more. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-php-memory-limit-for-nextcloud # NEXTCLOUD_TRUSTED_CACERTS_DIR: /path/to/my/cacerts # CA certificates in this directory will be trusted by the OS of the nexcloud container (Useful e.g. for LDAPS) See See https://github.com/nextcloud/all-in-one#how-to-trust-user-defined-certification-authorities-ca # NEXTCLOUD_STARTUP_APPS: deck twofactor_totp tasks calendar contacts notes # Allows to modify the Nextcloud apps that are installed on starting AIO the first time. See https://github.com/nextcloud/all-in-one#how-to-change-the-nextcloud-apps-that-are-installed-on-the-first-startup NEXTCLOUD_ADDITIONAL_APKS: imagemagick # This allows to add additional packages to the Nextcloud container permanently. Default is imagemagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-os-packages-permanently-to-the-nextcloud-container NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS: imagick # This allows to add additional php extensions to the Nextcloud container permanently. Default is imagick but can be overwritten by modifying this value. See https://github.com/nextcloud/all-in-one#how-to-add-php-extensions-permanently-to-the-nextcloud-container # NEXTCLOUD_ENABLE_DRI_DEVICE: true # This allows to enable the /dev/dri device in the Nextcloud container. ⚠️⚠️⚠️ Warning: this only works if the \u0026#39;/dev/dri\u0026#39; device is present on the host! If it should not exist on your host, don\u0026#39;t set this to true as otherwise the Nextcloud container will fail to start! See https://github.com/nextcloud/all-in-one#how-to-enable-hardware-transcoding-for-nextcloud # NEXTCLOUD_KEEP_DISABLED_APPS: false # Setting this to true will keep Nextcloud apps that are disabled in the AIO interface and not uninstall them if they should be installed. See https://github.com/nextcloud/all-in-one#how-to-keep-disabled-apps # TALK_PORT: 3478 # This allows to adjust the port that the talk container is using. See https://github.com/nextcloud/all-in-one#how-to-adjust-the-talk-port # WATCHTOWER_DOCKER_SOCKET_PATH: /var/run/docker.sock # Needs to be specified if the docker socket on the host is not located in the default \u0026#39;/var/run/docker.sock\u0026#39;. Otherwise mastercontainer updates will fail. For macos it needs to be \u0026#39;/var/run/docker.sock\u0026#39; # security_opt: [\u0026#34;label:disable\u0026#34;] # Is needed when using SELinux networks: - nextcloud # # Optional: Caddy reverse proxy. See https://github.com/nextcloud/all-in-one/blob/main/reverse-proxy.md # # You can find further examples here: https://github.com/nextcloud/all-in-one/discussions/588 # caddy: # image: caddy:alpine # restart: always # container_name: caddy # volumes: # - ./Caddyfile:/etc/caddy/Caddyfile # - ./certs:/certs # - ./config:/config # - ./data:/data # - ./sites:/srv # network_mode: \u0026#34;host\u0026#34; go-vod: image: radialapps/go-vod restart: always depends_on: - nextcloud-aio-mastercontainer environment: - NEXTCLOUD_HOST=https://next.domain.ru - NVIDIA_VISIBLE_DEVICES=all volumes: - /media/nextcloud:/mnt/ncdata:ro runtime: nvidia networks: - nextcloud volumes: # If you want to store the data on a different drive, see https://github.com/nextcloud/all-in-one#how-to-store-the-filesinstallation-on-a-separate-drive nextcloud_aio_mastercontainer: name: nextcloud_aio_mastercontainer # This line is not allowed to be changed as otherwise the built-in backup solution will not work networks: nextcloud: name: nextcloud external: true Пример динамической конфигурации для обратного прокси Traefik\nhttp: routers: nextcloud: entrypoints: - \u0026#34;https\u0026#34; rule: \u0026#34;Host(`subdomain.domain.ru`)\u0026#34; middlewares: - https-redirect - nextcloud-secure-headers tls: domains: - main: \u0026#34;subdomain.domain.ru\u0026#34; service: nextcloud services: nextcloud: loadBalancer: servers: - url: \u0026#34;http://your_vm_ip:11000\u0026#34; passHostHeader: true middlewares: crowdsec-bouncer: #if you use crowdsec forwardauth: address: http://bouncer-traefik:8080/api/v1/forwardAuth trustForwardHeader: true # https://github.com/goauthentik/authentik/issues/2366 middlewares-authentik: # if you use authentik forwardAuth: address: \u0026#34;http://authentik_server:9000/outpost.goauthentik.io/auth/traefik\u0026#34; trustForwardHeader: true authResponseHeaders: - X-authentik-username - X-authentik-groups - X-authentik-email - X-authentik-name - X-authentik-uid - X-authentik-jwt - X-authentik-meta-jwks - X-authentik-meta-outpost - X-authentik-meta-provider - X-authentik-meta-app - X-authentik-meta-version nextcloud-secure-headers: headers: hostsProxyHeaders: - \u0026#34;X-Forwarded-Host\u0026#34; referrerPolicy: \u0026#34;same-origin\u0026#34; customResponseHeaders: X-Robots-Tag: \u0026#34;noindex, nofollow\u0026#34; #changed from default \u0026#34;none\u0026#34; parameter https-redirect: redirectScheme: scheme: https permanent: true nextcloud-chain: chain: middlewares: # - ... (e.g. rate limiting middleware) - https-redirect - nextcloud-secure-headers Основные моменты моего файла # Nextcloud AIO\nКонтейнер: nextcloud-aio-mastercontainer\ncontainer_name и volumes с именем nextcloud_aio_mastercontainer менять нельзя - это правило для работы встроенного бэкапа.\nПорты:\n8087:8080 - значит веб-интерфейс будет доступен на http://host:8087.\nОстальные порты закомментированы, что нормально при использовании обратного прокси.\nПеременные окружения:\nNEXTCLOUD_DATADIR: /media/nextcloud и NEXTCLOUD_MOUNT: /media - правильно, чтобы Nextcloud и go-vod видели один и тот же каталог.\nAPACHE_PORT и APACHE_IP_BINDING настроены для обратного прокси.\nNEXTCLOUD_ADDITIONAL_APKS и NEXTCLOUD_ADDITIONAL_PHP_EXTENSIONS - добавили imagemagick и imagick, что будет полезно для обработки изображений.\ngo-vod\nЗависит от Nextcloud AIO (depends_on).\nИспользуется NVIDIA GPU (runtime: nvidia и NVIDIA_VISIBLE_DEVICES=all).\nvolumes: /media/nextcloud:/mnt/ncdata:ro - только для чтения, чтобы Go-VOD мог обрабатывать файлы Nextcloud без риска изменения.\nПеременная NEXTCLOUD_HOST=https://next.domain.ru - должна указывать на ваш реальный домен Nextcloud.\nСеть\nОба контейнера подключены к внешней сети nextcloud, что позволяет им общаться друг к другу по имени контейнера.\nVolumes\nnextcloud_aio_mastercontainer - важен для встроенного бэкапа.\nОстальные данные Nextcloud находятся в NEXTCLOUD_DATADIR.\nРекомендации / Проверки # GPU для go-vod:\nУбедитесь, что драйвер NVIDIA и nvidia-container-toolkit установлены на хосте.\nПроверьте, что контейнер видит GPU.\nПрава на каталог Nextcloud:\n/media/nextcloud должен быть доступен как для AIO, так и для go-vod.\nДля go-vod стоит использовать :ro (только для чтения), это безопасно.\nОбратный прокси:\nПорты 80/443 закомментированы, значит, нужно настроить внешний обратный прокси Nginx/Caddy/Traefik.\nAPACHE_PORT = 11000, убедитесь, что ваш прокси использует этот порт для проксирования.\nБэкап:\nНе трогайте volume nextcloud_aio_mastercontainer.\nМожно проверять резервные копии через AIO интерфейс.\nЗапуск и настройка Nextcloud AIO # Сохраните файл как docker-compose.yml.\nЗапустите команду:\ndocker compose up -d Перейдите в браузере по адресу: http://\u0026lt;IP_сервера\u0026gt;:8087 (порт 8087, а не дефолтный 8080 - именно так он и указан в docker-compose.yml выше)\nСледуйте мастеру установки: Укажите домен (например, cloud.prohomelab.com),\nНастройте HTTPS (через встроенный Let\u0026rsquo;s Encrypt или прокси),\nДождитесь автоматического развёртывания всех контейнеров.\nЗаключение # Nextcloud AIO - идеальный вариант для тех, кто хочет запустить мощное облако «в один клик». Он сочетает удобство Docker, автоматические обновления и надёжность официальной поддержки команды Nextcloud. Такой подход отлично подойдёт для домашнего сервера, LXC-контейнера в Proxmox или VPS, где важны простота, безопасность и автономность.\n","date":"25 October 2025","externalUrl":null,"permalink":"/posts/nextcloud-aio/","section":"Posts","summary":"Пошаговая инструкция по установке и настройке Nextcloud AIO для развертывания личного облачного сервера. Рассмотрены установка через Docker, настройка пользователей, хранилища и веб-интерфейса, а также интеграция с мобильными устройствами.","title":"Установка Nextcloud AIO - простое и мощное облако в Docker","type":"posts"},{"content":" Why merge local-lvm and local? # After installing Proxmox VE, two local storages are created by default:\nlocal - the /var/lib/vz folder, intended for ISO images, templates, and backups. local-lvm - an LVM pool where the disks of virtual machines and containers are stored. At first glance this is convenient, but this separation has downsides:\nThe size of local-lvm is fixed, and it\u0026rsquo;s hard to free up space for ISOs or backups. Files in local-lvm are not directly visible in the file system. Expanding or migrating the pool is problematic. That\u0026rsquo;s why many administrators prefer to merge local-lvm and local into a single file-based storage, where everything is stored as regular files.\nAvailable approaches # There are two approaches:\nRemove the LVM pool and use all the space for ext4 (or ZFS). Migrate the disks from local-lvm to local, then remove the LVM pool. We\u0026rsquo;ll go with the first option, since it\u0026rsquo;s simpler if you\u0026rsquo;re installing Proxmox from scratch - it\u0026rsquo;s safer, and you won\u0026rsquo;t lose data.\nStep 1. Remove the LVM storage from the Storage list in the Datacenter section of our Proxmox # Go to the Datacenter menu, select Storage, select the local-lvm storage we don\u0026rsquo;t need, and click the remove button.\nAs a result, we\u0026rsquo;re left with only the local storage. However, the problem is that the \u0026ldquo;supposedly\u0026rdquo; freed disk space isn\u0026rsquo;t actually freed yet.\nStep 2. Freeing up space # Go into the shell of our node and start the magic session.\nFirst, let\u0026rsquo;s actually remove the logical volume with the command\nlvremove /dev/pve/data and confirm the action.\nStep 3. Increasing the size of the logical volume # Now let\u0026rsquo;s use the following command to increase the size of the logical volume (LVM) so it takes up all the available unallocated space on the physical volume (PV).\nlvresize -l +100%FREE /dev/pve/root What does the command above mean, you ask me, my curious little friend. Good question.\nWhat happens step by step\nlvresize is a utility for resizing a Logical Volume in LVM. -l +100%FREE is a flag that says: \u0026ldquo;Add all the remaining free space from the volume group (VG) to this logical volume.\u0026rdquo; That is, if our pve group has, say, 50 GB of unused space left, this command will add all of it to /dev/pve/root.\n/dev/pve/root is the path to the logical volume where the main file system is installed (usually /).\nAnd finally, today\u0026rsquo;s last command\nStep 4. Expanding our file system # resize2fs /dev/mapper/pve-root expands our ext4 file system inside the specified partition.\nNow let\u0026rsquo;s check what we\u0026rsquo;ve done.\nAs you can see, now all disk space is used within a single local storage.\nBut there\u0026rsquo;s one more, final and mandatory, touch needed.\nStep 5. The final touch # We need to tell the system that the local storage should now be used for all data types, including the type that was previously only used by local-lvm.\nPost scriptum # If you enjoyed this article or found this knowledge useful, consider supporting the channel on Boosty via the link in the contacts.\n","date":"October 9, 2025","externalUrl":null,"permalink":"/en/posts/merge-local-lvm-and-local/","section":"Posts","summary":"A step-by-step guide to merging the local-lvm and local storages in Proxmox into a single logical storage. Covers the commands and settings that help you use space more efficiently and simplify management of virtual machines and containers.","title":"How to Merge local-lvm and local into a Single Storage in Proxmox","type":"posts"},{"content":"","date":"October 9, 2025","externalUrl":null,"permalink":"/en/tags/storage/","section":"Tags","summary":"","title":"Storage","type":"tags"},{"content":"","date":"September 29, 2025","externalUrl":null,"permalink":"/en/tags/cluster/","section":"Tags","summary":"","title":"Cluster","type":"tags"},{"content":" Storage for HA in Proxmox VE: an in-depth technical overview # Table of Contents # The Role of Storage in High Availability Scenario: single node + HA requirement Scenario: two nodes + quorum / witness Scenario: three or more nodes with shared storage Hyperconverged storage (Ceph, etc.) External SAN/NAS solutions Storage types not suited for HA Recommendations and best practices Conclusion 1. The Role of Storage in High Availability # In a Proxmox VE cluster, the High Availability (HA) mechanism ensures automatic restart of virtual machines or containers on other nodes when one of the servers fails. How well HA works directly depends on which storage is used.\nWhy the type of storage is critical for HA # When one node goes down, another must:\nhave access to the disks of the virtual machine (VM/CT); read the configuration; start the instance without data desynchronization. Storage requirements for an HA cluster # Shared access - the VM disk must be accessible from multiple nodes. Cluster-wide consistency - support for locking, protection against split-brain, synchronous/asynchronous replication. Failover without manual intervention - automatic VM startup on another node. Network requirements - a dedicated network for storage, 10GbE minimum recommended. Data reliability - RAID, Ceph replication, DRBD, fault-tolerant NAS/SAN. Support for the Proxmox HA stack - Ceph, iSCSI, NFS, ZFS replication, GlusterFS (not supported starting with Proxmox VE 9). 2. Scenario: single node + HA requirement # 2.1. Local storage with ZFS RAID or hardware RAID # Pros: disk protection, simplicity, performance Cons: no failover, HA is impossible 2.2. ZFS replication to a \u0026ldquo;passive\u0026rdquo; node # Allows for a so-called \u0026ldquo;cold standby,\u0026rdquo; but not HA - no automatic VM startup 2.3. Replication to an external NAS/storage array # Suitable for backups, but the NAS becomes an SPOF (single point of failure) 2.4. Snapshots + vzdump # Data recovery only, failover isn\u0026rsquo;t possible Conclusion: HA isn\u0026rsquo;t possible on a single node - a minimum of 2+ nodes with shared storage is required.\n3. Scenario: two nodes + quorum # 3.1. The problem with two nodes: split-brain # Without a third vote (QDevice), HA doesn\u0026rsquo;t work correctly. Solution: QDevice # Options: a separate VM, a mini-PC, PBS, Raspberry Pi After adding it → 3 votes, HA works 3.2. Storage for HA in a 2-node cluster # Storage HA Compatibility SPOF Requires QDevice Performance ZFS Local + Replication Yes (partially) Node Yes Medium NFS / iSCSI / NAS Yes NAS Yes Medium Ceph Yes No Yes High DRBD9 Yes No Yes Medium 4. Scenario: three or more nodes with shared storage # 4.1. Why things get simpler with 3+ nodes # Quorum is supported natively No split-brain when one node is lost Simple HA management 4.2. Shared storage # 4.2.1 NFS # File-based connection, suitable for VM/CT disks and ISOs The NAS is an SPOF (single point of failure). Losing connectivity to the NAS - all virtual machines shut down. 4.2.2 iSCSI # Block-level access, multipath for HA SAN SPOF is possible 4.2.3 SMB/CIFS # Only for ISOs/templates, not for VM disks 4.3. Hyperconverged storage # Ceph: RBD/FS, 3+ nodes, self-healing, block storage Architecture SPOF Performance Requirements Scalability HA Compatibility NFS NAS Medium Low Medium Yes iSCSI SAN High Medium Medium Yes Ceph None High High Excellent Yes 5. Hyperconverged storage (Ceph, etc.) # 5.1. Ceph # RBD for VM disks CephFS for ISOs, templates, backups Requires 3+ nodes, a dedicated network, SSD/NVMe 6. External SAN/NAS solutions # Type Description HA Compatibility Notes NAS (NFS/CIFS) File-based storage Yes (NFS) CIFS only for ISOs/templates SAN (iSCSI/Fibre Channel) Block-level access Yes Multipath is mandatory Unified Storage NFS + iSCSI Yes NAS/SAN clustering recommended Connection examples:\n# NFS Datacenter -\u0026gt; Storage -\u0026gt; Add -\u0026gt; NFS Server: IP NAS Export: /volume1/proxmox Content: Disk image, ISO, backup Nodes: all nodes # iSCSI Datacenter -\u0026gt; Storage -\u0026gt; Add -\u0026gt; iSCSI Target: IQN LUN Portal: IP SAN Nodes: all nodes Optionally: LVM over iSCSI 7. Storage types not suited for HA # Storage HA Compatibility Notes Local LVM/Directory none Single node only CIFS/SMB none ISOs/templates only Local ZFS without replication none Requires DR/replication Rsync / manual replication none No automatic failover 8. Recommendations and best practices # At least 3 nodes for quorum\nUse shared or hyperconverged storage\nA dedicated network for storage (10GbE)\nConfigure an HA group in Proxmox\nRegular backups using Proxmox Backup Server\nTest failover and monitor the system\nSynchronous replication for critical VMs\nDocument the architecture (so you don\u0026rsquo;t forget what you designed)\n9. Conclusion # A single node ≠ HA\nTwo nodes require a QDevice\nThree or more nodes is the optimal configuration\nThe choice of storage depends on your needs and budget: Ceph, DRBD, NAS/SAN (GlusterFS, as a native storage plugin, is no longer supported starting with Proxmox VE 9, but remains available via directory storage or a third-party plugin)\nAlways make sure to have backups and network redundancy\nFollowing these principles, a Proxmox VE cluster will be resilient, scalable, and provide automatic failover for critical VMs and containers.\n","date":"September 29, 2025","externalUrl":null,"permalink":"/en/posts/proxmox-cluster-types/","section":"Posts","summary":"An overview of the main types of storage in Proxmox with support for High Availability (HA). Covers local-lvm, Ceph, NFS, and other solutions, their advantages and limitations, plus recommendations for choosing a reliable and scalable cluster.","title":"Storage for HA in a Proxmox Cluster","type":"posts"},{"content":"","date":"22 September 2025","externalUrl":null,"permalink":"/tags/devops/","section":"Tags","summary":"","title":"DevOps","type":"tags"},{"content":"","date":"22 September 2025","externalUrl":null,"permalink":"/tags/iac/","section":"Tags","summary":"","title":"IaC","type":"tags"},{"content":"","date":"22 September 2025","externalUrl":null,"permalink":"/categories/terraform/","section":"Categories","summary":"","title":"Terraform","type":"categories"},{"content":"","date":"22 September 2025","externalUrl":null,"permalink":"/tags/terraform/","section":"Tags","summary":"","title":"Terraform","type":"tags"},{"content":"","date":"22 September 2025","externalUrl":null,"permalink":"/tags/%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F/","section":"Tags","summary":"","title":"Автоматизация","type":"tags"},{"content":"","date":"22 September 2025","externalUrl":null,"permalink":"/series/%D0%B0%D0%B2%D1%82%D0%BE%D0%BC%D0%B0%D1%82%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F-%D0%B2-proxmox/","section":"Series","summary":"","title":"Автоматизация В Proxmox","type":"series"},{"content":" Ниже приведен файл, который я использовал в ролике, посвященный установке и развертыванию сразу трех виртуальных машин с помощью Terraform\nvariable vm_configs { type = map(object({ vm_id = number name = string cores = number memory = number vm_state = string })) default = { \u0026#34;youtube-1\u0026#34; = { vm_id = 357, name = \u0026#34;youtube-1\u0026#34;, cores = 1, memory = 2048, vm_state = \u0026#34;stopped\u0026#34;} \u0026#34;youtube-2\u0026#34; = { vm_id = 358, name = \u0026#34;youtube-2\u0026#34;, cores = 1, memory = 4096, vm_state = \u0026#34;stopped\u0026#34;} \u0026#34;youtube-3\u0026#34; = { vm_id = 359, name = \u0026#34;youtube-3\u0026#34;, cores = 1, memory = 2048, vm_state = \u0026#34;running\u0026#34;} } } resource \u0026#34;proxmox_vm_qemu\u0026#34; \u0026#34;youtubetestvms\u0026#34; { for_each = var.vm_configs vmid = each.value.vm_id name = each.value.name target_node = \u0026#34;belisarius\u0026#34; clone = \u0026#34;ubuntutemplate\u0026#34; full_clone = true bios = \u0026#34;ovmf\u0026#34; agent = 1 scsihw = \u0026#34;virtio-scsi-single\u0026#34; os_type = \u0026#34;ubuntu\u0026#34; cpu_type = \u0026#34;x86-64-v2-AES\u0026#34; cores = each.value.cores sockets = 1 memory = each.value.memory vm_state = each.value.vm_state disks { scsi { scsi0 { disk { size = \u0026#34;32G\u0026#34; storage = \u0026#34;local\u0026#34; format = \u0026#34;qcow2\u0026#34; } } } } network { id = 0 model = \u0026#34;virtio\u0026#34; bridge = \u0026#34;vmbr0\u0026#34; } } ","date":"22 September 2025","externalUrl":null,"permalink":"/posts/terraform-proxmox-3vm-automation/","section":"Posts","summary":"Пошаговое руководство по автоматической установке нескольких виртуальных машин в Proxmox 9.0.3 с использованием Terraform в Docker. Рассмотрены настройка окружения, создание конфигураций Terraform и автоматизация развертывания VM для ускорения работы с Proxmox.","title":"Автоматическая установка нескольких виртуальных машин в Proxmox 9.0.3 с помощью Terraform в Docker","type":"posts"},{"content":" What is a cluster in Proxmox # A cluster in Proxmox VE is the combination of several physical nodes into a single management system. This allows you to centrally manage virtual machines and containers, perform migrations between hosts, configure HA (High Availability), and distribute load.\nThe main goal is to increase fault tolerance and ease of administration.\nWhat is Quorum # Quorum is a voting mechanism inside a Proxmox cluster that determines whether the cluster can operate.\nEach cluster node has one vote. For the cluster to function, more than half of the votes are needed. If there\u0026rsquo;s no quorum, operations on virtual machines and containers are blocked to avoid split-brain (a situation where nodes start operating independently and conflict with each other). Examples: # 2 nodes → 2/2 votes needed. If one goes down, there\u0026rsquo;s no quorum. 3 nodes → 2/3 votes is enough. 4 nodes → 3/4 needed. 5 nodes → 3/5 is enough. Checking quorum # pvecm status The output will show:\nQuorate: Yes/No - whether there\u0026rsquo;s quorum,\nNodes - the number of nodes,\nExpected votes - how many votes are needed,\nTotal votes - how many there are currently.\nA two-node cluster # The minimum possible configuration is a cluster of two nodes. However, keep in mind that for the voting (quorum) system to work correctly, it\u0026rsquo;s better to use an odd number of participants.\nIn a two-node cluster, situations can arise where, if the connection between nodes is lost, Proxmox can\u0026rsquo;t determine who\u0026rsquo;s \u0026ldquo;right.\u0026rdquo; In that case, split-brain kicks in, which is risky for data.\nThis setup is suitable for test benches or a lab, but is not recommended for production.\nA two-node cluster + QDevice # To stabilize the operation of a two-node cluster, a QDevice (Quorum Device) is used. This is a separate server or virtual machine that doesn\u0026rsquo;t act as a hypervisor but participates in voting. Put more simply, it acts as an arbiter to prevent a split-brain situation from occurring.\nHow it works:\nNode 1 Node 2 QDevice Now the total number of votes is three, and the system can correctly determine who\u0026rsquo;s \u0026ldquo;alive.\u0026rdquo; This option is already suitable for production environments if you only have two servers.\nA cluster of three or more nodes # The classic and most stable scenario is a cluster of three nodes.\nAdvantages:\nThere\u0026rsquo;s always an odd number of votes. The failure of one node doesn\u0026rsquo;t break the cluster. You can use migration and HA. When scaling to 5, 7, or more nodes, you gain flexibility and scalability.\nThe main thing to remember:\nfor quorum to work, it\u0026rsquo;s enough that more than half of the nodes are available; it\u0026rsquo;s recommended to have at least three servers for a reliable cluster. A cluster of mixed hardware # Proxmox doesn\u0026rsquo;t require identical hardware for a cluster. You can combine:\nserver machines with ECC memory, home mini-PCs (for example, Intel NUCs or cheap Chinese boxes), even old workstations. However, there are nuances:\nVM migration: if the processors differ significantly (Intel ↔ AMD), you\u0026rsquo;ll need to configure CPU compatibility, or migration won\u0026rsquo;t be possible. Performance: weaker nodes won\u0026rsquo;t be able to handle the same load as server-grade ones. That is, if a lot of VMs suddenly migrate from a \u0026ldquo;powerful\u0026rdquo; node, a weak node will simply become unusable due to the load. Network and disks: it\u0026rsquo;s better to have a single fast channel (1/10/25 Gbit) and identical storage for optimal operation. Such a hybrid cluster is often used for a home lab environment.\nConclusion # 2 nodes - only for testing or a home environment. I use this myself. 2 nodes + QDevice - a working option for a small cluster. 3+ nodes - the optimal solution for fault tolerance. Mixed hardware can be used, but it\u0026rsquo;s important to consider CPU and performance limitations. Proxmox makes the process of creating a cluster simple and accessible - even for small home setups.\n","date":"September 12, 2025","externalUrl":null,"permalink":"/en/posts/proxmox-cluster/","section":"Posts","summary":"A detailed guide to building and configuring a cluster in Proxmox. Covers steps for joining multiple nodes, setting up highly available virtual machines and containers, plus basic recommendations for cluster management and monitoring.","title":"Proxmox Cluster: setup, QDevice, and mixed hardware in nodes","type":"posts"},{"content":"","date":"10 September 2025","externalUrl":null,"permalink":"/tags/ceph/","section":"Tags","summary":"","title":"Ceph","type":"tags"},{"content":"Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nЕсли вы увлекаетесь хоумлаббингом и начинаете собирать домашний сервер на базе Proxmox, то наверняка рано или поздно сталкивались с вопросом: а не поднять ли сразу Ceph для хранения данных? Идея выглядит заманчиво - отказоустойчивый кластер, автоматическая репликация, модный распределённый storage, тот же движок, который используют в датацентрах. У меня самого в какой-то момент чесались руки его попробовать.\nНо если честно ответить себе на вопрос, зачем он нужен именно дома, в 9 случаях из 10 ответа не находится. У меня в итоге один сервер под Proxmox и отдельная машина под Proxmox Backup Server с NAS по NFS для долгосрочного хранения - и этого с запасом хватает. Ceph я не поднимал и пока не жалею. Давайте разберусь, почему для домашнего сценария это чаще всего лишняя сложность - и не только потому, что сама технология не самая простая в освоении.\nЧто такое Ceph и зачем он вообще нужен # Ceph - это распределённое хранилище с открытым исходным кодом, которое объединяет диски нескольких серверов в единый отказоустойчивый пул. Данные автоматически реплицируются между узлами: если один сервер выходит из строя, данные остаются доступны на остальных, а кластер сам перераспределяет нагрузку без вмешательства администратора.\nИменно это и делает Ceph золотым стандартом для дата-центров и enterprise-инфраструктуры, где простой в принципе недопустим, а серверов и так уже десятки. Но у homelab, при всём уважении, задачи обычно совсем другие.\nПочему Ceph избыточен для домашнего Proxmox # 1. Минимальные требования не про homelab # Официальная рекомендация для рабочего Ceph-кластера - минимум три ноды, а для по-настоящему production-уровня отказоустойчивости - и вовсе пять. На каждую ноду желательно иметь минимум 4 диска под OSD, отдельную сеть под кластерный трафик со скоростью 10GbE и выше (на 2.5GbE ещё можно жить с оговорками, а вот 1 Гбит/с превращает Ceph в мучение), плюс SSD/NVMe под журналы, если хочется приемлемой производительности.\nДома же типичная картина - один сервер, максимум два. Городить три-четыре железки ради того, чтобы хранить медиатеку и пару десятков контейнеров - решение сомнительное, особенно если посчитать расходы на дополнительное железо, управляемые свитчи под 10GbE, кабели и шум от лишних вентиляторов в квартире.\n2. Сложность настройки и обслуживания # Ceph - это не диск, который просто примонтировали. Это мониторы (MON), менеджеры (MGR), OSD-демоны на каждом диске, отдельная сеть для служебного трафика (public и cluster network) и своя логика распределения данных (CRUSH map). Даже если удастся развернуть всё это на домашнем железе, обслуживание превращается в отдельную постоянную задачу: следить за состоянием OSD, вовремя обновлять компоненты, разбираться, почему кластер вдруг ушёл в HEALTH_WARN.\nДля энтузиаста, который просто хочет, чтобы его Jellyfin и пара контейнеров стабильно работали по вечерам, это заметно больше мороки, чем пользы.\n3. Производительность в маленьких масштабах # Ceph раскрывает свой потенциал только при достаточном количестве нод, дисков и высокой скорости сети - вся архитектура заточена под горизонтальное масштабирование, а не под один-два сервера. В маленьких конфигурациях он, наоборот, часто оказывается медленнее локального ZFS-пула: репликация и сетевые накладные расходы съедают то преимущество в скорости, которое дают локальные NVMe-диски.\n4. Электричество и шум # Каждая дополнительная нода - это не только деньги на само железо, но и постоянная статья расходов на электричество. Три-четыре сервера, которые круглосуточно крутятся только ради того, чтобы обслуживать Ceph-кластер, для домашнего использования почти никогда не окупаются - ни по деньгам, ни по уровню шума в квартире или гараже.\nАльтернативы Ceph для домашнего Proxmox # Решение Преимущества Недостатки Оптимально для ZFS Простая настройка, снапшоты, RAID-Z, самовосстановление данных (scrub) Требует больше RAM Один сервер с надёжным локальным хранилищем NAS (TrueNAS, Unraid, OMV) Централизованное хранение, удобный веб-интерфейс, NFS/iSCSI/SMB Отдельное устройство, дополнительные расходы на железо Отдельный сервер для данных + Proxmox для вычислений Локальные диски Простота, минимальная стоимость Нет отказоустойчивости на уровне узла Маленькие тестовые стенды Я в итоге пришёл именно к связке \u0026ldquo;локальный SSD под быстрые данные + отдельный NAS по сети под бэкапы и архив\u0026rdquo; - и для домашнего сценария она закрывает 95% задач без единой строчки настроек Ceph.\nКогда Ceph всё-таки имеет смысл даже дома # Справедливости ради, есть сценарии, где Ceph оправдан и в домашних условиях:\nу вас уже есть три и более сервера не только под Proxmox, но и просто \u0026ldquo;лежат без дела\u0026rdquo;; вам действительно важна миграция ВМ между нодами без общего хранилища на базе NFS/iSCSI; вы сознательно хотите потренироваться на Ceph, потому что работаете с ним на основной работе и homelab - для вас учебный полигон. Если ни один из пунктов не про вас - Ceph можно смело отложить и не грузить себя лишней сложностью.\nИтог # Ceph - отличная технология, но она раскрывает себя в крупных инфраструктурах, где нужна настоящая отказоустойчивость и горизонтальное масштабирование на десятках дисков. В домашнем Proxmox это почти всегда избыточно. Лучше вложиться в качественные диски, продуманное резервное копирование (я, например, использую для этого отдельный Proxmox Backup Server - писал об этом отдельно) и UPS, чем тратить вечера на развёртывание и последующее обслуживание кластера Ceph ради одного-двух домашних серверов.\nFAQ # Можно ли поднять Ceph на одном сервере? # Технически можно, но смысла в этом немного. Ceph задуман как кластерная система, и на одном узле он не даст никаких преимуществ перед ZFS или локальными дисками - только лишние накладные расходы.\nЧто лучше для домашнего Proxmox: ZFS или Ceph? # Для подавляющего большинства домашних сценариев ZFS проще, надёжнее в эксплуатации и дешевле по железу. Ceph оправдан только при наличии как минимум трёх, а лучше пяти серверов.\nКак хранить виртуальные машины Proxmox дома без Ceph? # Самый практичный вариант - локальные диски с ZFS на самом сервере Proxmox, либо отдельный NAS, подключённый по NFS или iSCSI, для данных, которые не обязаны жить на самом быстром хранилище.\nТакже по теме # Хранилище для HA в кластере Proxmox Proxmox Backup Server: установка и настройка ","date":"10 September 2025","externalUrl":null,"permalink":"/posts/proxmox-ceph-home/","section":"Posts","summary":"Разбор причин, почему Ceph может быть избыточным для домашнего использования. Рассмотрены сложности в настройке и обслуживании, затраты ресурсов и рекомендации по более простым и эффективным альтернативам для домашнего сервера и Proxmox.","title":"Почему мне не нужен Ceph storage в Proxmox для домашнего сервера","type":"posts"},{"content":" Настройка Firewall в Proxmox # Proxmox VE - это мощная платформа виртуализации, которая объединяет в себе возможности KVM и LXC, а также средства для кластеризации и управления хранилищами. Одним из ключевых инструментов обеспечения безопасности в Proxmox является встроенный firewall.\nВ этой статье мы разберём:\nчто такое firewall и зачем он нужен в Proxmox, его плюсы и минусы, как настроить базовые правила для защиты узла и виртуальных машин. Что такое Firewall в Proxmox # Firewall (межсетевой экран) - это система фильтрации сетевого трафика, которая позволяет управлять входящими и исходящими соединениями. В Proxmox используется iptables/nftables как backend, а управление правилами осуществляется через веб-интерфейс или CLI.\nFirewall в Proxmox может работать на трёх уровнях:\nDatacenter - глобальные правила для всего кластера. Node (узел) - правила, которые применяются к конкретному серверу. VM/CT (виртуальная машина или контейнер) - отдельные правила для каждой виртуальной машины. Если у вас не включен firewall на уровне Datacenter, то и на других уровнях (ноды или вм/lxc) он тоже не работает. Поэтому необязательно снимать соответствующую галку в настройках вновь создаваемых виртуальных машинах.\nЗачем нужен Firewall в Proxmox # В принципе в домашних условиях я не вижу смысла в использовании встроенного firewall в Proxmox, потому что дома вы скорее всего настраиваете правила на глобальном уровне (на уровне маршрутизатора). В домашних условиях, если конечно вы не живете в датацентре, нет необходимости настраивать firewall на уровне Proxmox. Но раз уж мы с вами полезли в кроличью нору SDN в Proxmox, то давайте разберем, что может firewall в Proxmox.\nИспользование встроенного firewall позволяет:\nограничить доступ к управляющему интерфейсу Proxmox, защитить виртуальные машины и контейнеры от нежелательного трафика, сегментировать сеть и контролировать взаимодействие сервисов, снизить риск атак (DDoS, brute-force, сканирование портов и т. д.). Плюсы и минусы использования Firewall в Proxmox # Плюсы # Централизованное управление правилами через веб-интерфейс. Возможность задавать правила на уровне кластера, ноды (узла) и VM. Поддержка групп правил (Firewall Groups), что упрощает масштабирование. Интеграция с Proxmox - не нужно настраивать отдельные правила firewall внутри каждой VM. Минусы # Требует понимания логики iptables/nftables. Ограниченные возможности мониторинга в сравнении с внешними системами. Ошибочные правила могут заблокировать доступ к самому Proxmox. Не заменяет полноценные решения вроде pfSense или OPNsense (но хорошо дополняет их в случае необходимости). Настройка Firewall в Proxmox # Как указано выше, по умолчанию firewall в Datacenter отключен.\nWarning Ни в коем случае не активируйте firewall в Datacenter, пока не настроите первые три правила о которых ниже. По умолчанию в firewall отсутствуют сконфигурированные правила. Это означает, что все запрещено. Включение firewall без предварительно сконфигурированных правил лишит вас доступа к web интерфейсу Proxmox. А значит выпадет тебе, милАй, дорога дальная с клавиатурой и монитором к физическому устройству.\nВключение Firewall в Datacenter и настройка трех основных правил # Перейдите в Datacenter → Firewall → Options и нажмите Add. Правило 1: Разрешить доступ к веб-интерфейсу Proxmox # В разделе Rules добавьте правило: Action: ACCEPT Direction: IN Interface: vmbr0 Protocol: tcp Destination Port: 8006 Comment: Allow WebGUI from home Жмем add\nВ разделе Firewall идем подменю Options и включаем firewall\nСейчас нам надо проверить, что мы не потеряли доступ к веб-интерфейсу нашего Proxmox. Просто обновим страницу, и если доступ на месте, то мы в игре. Ура!\nТеперь надо добавить еще два правила: нужно разрешить запросы от DHCP и запросы по протоколу http или dns, так как сейчас единственное что разрешено, это доступ к веб-интерфейсу.\nПравило 2: Разрешить запросы по DHCP # В разделе Rules добавьте правило: Action: ACCEPT Direction: IN Macro: DHCPfwd Comment: Allow DHCP requests Жмем add\nПравило 3: Разрешить запросы по DNS # В разделе Rules добавьте правило: Action: ACCEPT Direction: IN Macro: DNS Comment: Allow DNS requests Жмем add\nСейчас мы с вами сконфигурировали три базовых правила для firewall на уровне Datacenter. Если вы хотите использовать firewall в Proxmox по полной, то это базовые и обязательные правила. Обсуждению этот момент не подлежит.\nТак как firewall обрабатывает правила в порядке очередности сверху вниз, то правило для веб-интерфейса у нас должно идти первым, потом правило с DHCP, а потом правило про DNS. Я так думаю(с) Мимино\nВ тоже время, так как эти правила сформированы на уровне Datacenter, то они применяются даже в случае, если у вас есть кластер из двух или трех нод Proxmox\nСоздание alias и security groups в Proxmox # Мы с вами настроили правила на уровне Datacenter и там же активировали firewall.\nОднако, если мы с вами спустимся на уровень ноды и зайдем в раздел firewall, то увидим, что несмотря на то, что мы еще не настраивали правила на уровне ноды, firewall там уже активирован.\nТут есть один очень важный момент. Если у вас кластер, то firewall, как вы понимаете, включается автоматом на всех нодах кластера. А так как у нас, в настоящий момент, никаких правил еще не настроено, то трафик между нодами по умолчанию запрещен. Может конечно оно вам так и надо, но предположим, что у вас есть ceph хранилище, оно у вас тут же отвалится без правильной настройки правил firewall. Давайте это поправим. Сначала создадим пару, тройку alias, чтобы нам было проще работать с правилами.\nПерейдите в Datacenter → Firewall → Alias и нажмите Add. Создаем alias для локальной сети # В разделе alias пишем следующее: Name: local-network IP/CIDR: 192.168.1.0/24 Comment: по желанию Если с именем все понятно, то что касается сети, - я указал всю свою локальную сеть. У вас и диапазон может быть другим, так и требования могут соответствующие. Меняйте их исходя из ваших потребностей. Например, вы хотите разрешить трафик только между нодами и все. Но так как я показываю простые и базовые вещи, то и действую соответственно.\nСоздаем Alias для виртуальной сети\nВ разделе alias пишем следующее: Name: virt-network IP/CIDR: 11.11.11.0/24 Comment: по желанию Но в данном случае я указываю диапазон VNET сети. В предыдущей статье мы с вами задали ей адрес в диапазон 11.11.11.0/24\nСоздаем alias для шлюза нашей физической локальной сети\nВ разделе alias пишем следующее: Name: gateway IP/CIDR: 192.168.1.1 Comment: по желанию После того, как мы с вами для облегчения дальнейшей работы создали три alias, теперь создадим Security Groups\nПерейдите в Datacenter → Firewall → Security Groups и нажмите Create. Создаем Security Groups # Создаем группу для локальной сети\nТеперь переходим в окошко нашей группы и создаем правило\nПерейдите в Datacenter → Firewall → Security Groups - Rules и нажмите Add. Создадим правило для нашей Security Group, куда входит наша локальная сеть.\nПравило 1: Разрешить входящий трафик из нашей локальной сети # В разделе Rules добавьте правило: Action: ACCEPT Direction: IN Source: local-network Comment: по желанию Жмем Enable, а затем Add\nПравило 2: Разрешить исходящий трафик в нашу локальную сеть # В разделе Rules добавьте правило: Action: ACCEPT Direction: OUT Destination: local-network Comment: по желанию Жмем Enable, а затем Add\nТо есть, мы с вами разрешили любой трафик от наших устройств из локальной сети к ноде и обратно.\nНастройка основных правил на уровне ноды Proxmox # Перейдите в Datacenter → Название вашей ноды → Firewall → Insert Security Groups и нажмите Add. В ниспадающем окошке выбираете нашу группу, ставим галку напротив Enable и жмем Add\nСоответственно, если у вас несколько нод, то на каждой ноде повторите соответствующее действие.\nТеперь у нас в меру открытый firewall.\nЕсли же вам нужны более тонкие настройки, то руки у вас развязаны, дерзайте.\nНастройка основных правил на уровне VM или LXC в Proxmox # Давайте перейдем к настройками firewall на уровне создаваемых машин или контейнеров в Proxmox\nПереходим в Datacenter → Название вашей ноды → Firewall → Insert Security Groups и нажмите Add. Создаем Security Group, как в предыдущем пункте, но в отношении виртуальной сети. Я ее назвал virt-network\nВыбираем вновь созданную группу, переходим в раздел Rules и создаем первое правило.\nНапример мы хотим запретить доступ от наших виртуальных машин или контейнеров в нашу локальную сеть\nВ разделе Rules добавьте правило: Action: DROP Direction: OUT Destination: local-network Comment: по желанию Но, но, запретив доступ нашим ВМ или контейнерам к локальной сети, мы одновременно запретили доступ им и во внешний мир, так как наш шлюз находится в том же диапазоне адресов, что и диапазон к которому мы запретили доступ. Поэтому мы с Вами создаем еще одно правило.\nВ разделе Rules добавьте правило: Action: ACCEPT Direction: OUT Destination: gateway Comment: по желанию Обратите внимание на порядок правил. Разрешающее правило должно быть выше запрещающего\nНу и опционально, просто для наглядности, давайте добавим еще одно, дополнительное правило. Что называется для закрепления материала.\nВ разделе Rules добавьте правило: Action: ACCEPT Direction: in Source: local-network Comment: по желанию То есть мы разрешили входящий трафик из локальной сети в нашу виртуальную сеть. Да, какого-то смысла все запретить и тут же все разрешить нет. Но, как я и сказал выше, - это просто для наглядности и понимания принципов работы firewall\nВ итоге у нас сейчас три правила\nМы разрешаем входящий трафик из локальной сети. Мы разрешаем трафик во внешний мир, потому что мы разрешили исходящий трафик на адрес нашего шлюза. Мы запретили исходящий трафик из нашей виртуальной сети в нашу локальную сеть. Так что никакие виртуальные машины или контейнеры не имеют доступа к нашим устройствам в нашей физической локальной сети.\nНо пока эти правила не работают.\nЧто я имею в виду.\nИдем с вами в командную строку, в моем случае, контейнера на базе Ubuntu и пропингуем машину, с которой я сейчас пишу настоящую статью\nКак вы видите пинг проходит. Это из-за того, что мы не включили firewall на уровне контейнера. Поэтому в меню нашего контейнера идем в Firewall → Options и включаем firewall\nПоднимаемся в меню firewall нашего контейнера и активируем нашу security group для виртуальной сети.\nИ теперь когда мы с вами опять попробуем пропинговать нашу машину, то ответом нам будет тишина, так как машина в локальной сети не входит в группу для виртуальной сети\nНо если мы например решим выйти во внешний мир и пропингуем что-то типа ya.ru, то сигнал пройдет\nНо как известно, во всем всегда виноват dns, и чтобы избежать ситуации, когда мы можем пропинговать какой-то айпи во внешний мир, но не можем пропинговать доменное имя, создадим еще одно правило для Security Group на уровне Datacenter, которым мы разрешим доступ к DNS\nНа этом я хотел бы закончить первоначальную настройку firewall в Proxmox. Но напоследок хотел бы повторить про лучшие практики настройки правил в firewall\nЛучшие практики настройки правил firewall для начинающих # Всегда начинайте с ALLOW правил, затем переходите к блокировке (DROP). Используйте Firewall Groups для удобства управления (например, ssh-access, web-access). Тестируйте правила пошагово, чтобы случайно не заблокировать доступ. Для продакшн-окружения используйте firewall Proxmox вместе с внешним firewall (pfSense, OPNsense, iptables на роутере). Выводы # Firewall в Proxmox - это мощный инструмент для повышения безопасности вашего кластера и виртуальных машин. Он позволяет централизованно управлять доступом, фильтровать трафик и минимизировать риски атак. Несмотря на некоторые ограничения, встроенный firewall отлично подходит для большинства сценариев в homelab и малых продакшн-системах.\n","date":"7 September 2025","externalUrl":null,"permalink":"/posts/proxmox-firewall/","section":"Posts","summary":"Подробная инструкция по настройке встроенного фаерволла Proxmox для защиты виртуальных машин и контейнеров. Рассмотрены создание правил, настройка сетевых зон, управление трафиком и рекомендации по обеспечению безопасности кластера.","title":"Как настроить Firewall в Proxmox VE | Пошаговая инструкция","type":"posts"},{"content":" В Proxmox VE SDN (Software Defined Networking) - это подсистема для управления виртуальными сетями, добавленная начиная с версии 7. Она упрощает работу с сетевой инфраструктурой внутри кластера и позволяет организовывать гибкие, изолированные и масштабируемые сети для виртуальных машин и контейнеров.\nОсновные моменты про SDN в Proxmox # 1. Зачем нужно SDN # Упрощает создание частных сетей внутри кластера Proxmox. Позволяет изолировать трафик разных пользователей или проектов. Дает возможность масштабировать сеть на несколько узлов кластера. Автоматизирует настройку маршрутизации, NAT, DHCP и DNS. 2. Компоненты SDN в Proxmox # Zones (зоны) - логические сегменты сети (например, для разных проектов или клиентов). VNet (виртуальные сети) - создаются внутри зон и определяют топологию L2/L3. Controllers (контроллеры) - управляют сетевыми настройками (например, через EVPN, VXLAN, BGP). IPAM/DNS - встроенная система для управления IP-адресами и именами. 3. Поддерживаемые типы зон # Simple (VLAN-aware bridge) - обычная сеть на базе bridge + VLAN. VXLAN - оверлейная сеть с туннелированием поверх IP. EVPN - продвинутый вариант для интеграции с \u0026ldquo;датацентровой\u0026rdquo; сетью через BGP. QoS zones - поддержка ограничений пропускной способности. 4. Пример использования # У вас есть кластер Proxmox на 3 узла. Вы создаете SDN-зону типа VXLAN, чтобы виртуалки на разных хостах оказались в одной L2-сети. Proxmox сам поднимает туннели между узлами, и ВМ/контейнеры видят друг друга, как будто они в одной локальной сети. Конкуренты # SDN в Proxmox позволяет строить облачные сценарии наподобие OpenStack/VMware NSX, но в более простом виде.\nОсобенности статьи # В данной статье, которая идет как дополнение к видео в начале текста, я постараюсь рассмотреть базовую конфигурацию SDN, которая даст нам понимание как работает SDN в Proxmox\nВводные # SDN в Proxmox по умолчанию появилась начиная с версии Proxmox 8.1. В случае если у вас система более старая, то сначала вам надо будет ввести в шелле вашей ноды следующую команду, чтобы установить необходимые пакеты:\napt update apt install libpve-network-perl После установки необходимо убедиться, что следующая строка присутствует в конце файла конфигурации /etc/network/interfaces на всех нодах (в случае если у вас кластер), чтобы конфигурация SDN была включена и активирована\nsource /etc/network/interfaces.d/* Интеграция DHCP во встроенный стек управления IP-адресами PVE в настоящее время использует dnsmasq для выдачи DHCP-аренды. Чтобы использовать эту функцию, вам необходимо установить пакет dnsmasq на каждой ноде.\napt update apt install dnsmasq # disable default instance systemctl disable --now dnsmasq #отключаем dhcp сервер, чтобы он не конфликтовал с вашим роутером Первоначальная настройка SDN # В меню Datacenter кликаете на вкладку SDN. Там вы видите список сетей, которые существуют на данный момент. Количество сетей будет зависеть от количество нод. В моем случае будет только одна локальная сеть.\nТеперь давайте создадим свою первую (так-то она конечно вторая по счету) локальную сеть. Идем в раздел Zones, жмем кнопку add и видим, что можем выбрать разные типы зон.\nТак как у нас с вами будет базовая/простая конфигурация, - то выбираем simple.\nВ качестве ID я указываю название youtube. Значения MTU я оставлю по умолчанию. Обратите внимание, иногда регионы рапортуют, что с дефолтным значением MTU, которое равняется 1500, могут быть проблемы. Можете попробовать значение 1460 как вариант. В этом же меню в качестве DHCP я выбираю автонастройку. Жмем add. В итоговом окошке видим настройки нашей зоны. Теперь идем в раздел VNET, жмем кнопку create.\nВыбираем имя и alias который вы хотите. Теперь выбираете вновь созданную зону. Все остальное оставляем по умолчанию, потому что в этой статье, как сказано выше, мы делаем только базовую настройку, никаких vlan и прочего. Мы с вами создали нашу первую виртуальную сеть. После того как мы с вами ее создали, у нас появилось новое меню подсеть. В меню vnet выбираем нашу вновь созданную сеть, переходим в меню подсеть subnet. Жмем создать. Сейчас мы с вами создадим нашу подсеть, которая будет изолирована от нашей домашней сети.\nЗадаем адрес нашей подсети. Я люблю нечетные числа, поэтому задам адрес 11.11.11.0/24 (но это неправильно с точки зрения использования в production среде). Адрес шлюза - 11.11.11.1. Нам нужно поставить галку в разделе snat. Это позволит всем устройствам подсети иметь единый внешний айпи адрес, чтобы они имели выход во внешний мир. Днс не трогаем.\nWarning Правильно создавать сети в пределах диапазона частных сетей для избежания разных неприятных сюрпризов! Поэтому лучше создавать все в пределах 10.10.10.0/24. Но так как наша вновь созданная подсеть должна быть изолирована от доступа из внешнего мира без отдельного на то разрешения, то и так сойдет.\nТеперь нам надо задать диапазон адресов в меню DHCP. Не будем изобретать велосипед, зададим диапазон от 100 до 199. Жмем create.\nМы с вами создали зону, vnet, subnet. Теперь чтобы изменения были применены идем в меню SDN и жмем apply. Теперь когда вы перейдете в список сетей вашей ноды, вы увидите что рядом с localnetwork появилась вновь созданная сеть. Все, мы с вами сделали первые шаги, чтобы создать основу для нашей маленькой SDN.\nЧтобы проверить как все оно работает в реальности - создадим для тестовых задач простой и пустой LXC контейнер на базе Ubuntu. Все делаем как обычно, кроме одного маленького, но очень важного, момента. Когда мы с вами выбираем мост (bridge) который будет использовать наш контейнер в разделе bridge\nвыбираем не vmbr0, к которому мы с вами привыкли, а вновь созданную сеть. Все остальное оставляем как обычно. Уже сейчас вы можете вернуться в Datacenter, и в подменю IPAM увидеть сетевые данные вновь созданного контейнера.\nВ нашем случае у него теперь ip адрес 11.11.11.100 После создания и запуска контейнера мы должны проверить - имеет ли наш контейнер выход во внешний мир. Вы конечно можете это сделать простой командой ping нужный ресурс, но достаточно будет просто запустить apt update, и в случае если все в порядке, то контейнер проверит наличие обновлений и выдаст вам результат. Уже это подтверждает, что у вас полностью рабочий контейнер, который имеет доступ во внешний мир. Теперь удостоверимся, что наш контейнер не доступен из внешнего мира. С любой машины внутри вашей локальной сети, но не из шелла Proxmox пропингуем наш контейнер ping 11.11.11.100 и ответом нам будет тишина. Все потому, что, как я и указывал в начале статьи, наш с вами контейнер находится в изолированной от внешнего мира сети (SDN). Необходимо отметить, что если вы будете пинговать контейнер из шелла вашей ноды, то в данном случае контейнер будет доступен. Это связано с тем, что сеть создана внутри нашей ноды, каких-либо правил firewall мы еще не настраивали, поэтому с ноды наш контейнер замечательно пингуется. Однако настройка firewall внутри Proxmox - это тема уже другой статьи.\n","date":"31 August 2025","externalUrl":null,"permalink":"/posts/proxmox-sdn-guide/","section":"Posts","summary":"Подробная инструкция по настройке SDN в Proxmox для централизованного управления виртуальными сетями. Рассмотрены создание виртуальных сетевых сегментов, настройка VXLAN, интеграция с фаерволлом и рекомендации по управлению сетевыми ресурсами.","title":"Proxmox SDN: Полное руководство по настройке и использованию","type":"posts"},{"content":"","date":"18 August 2025","externalUrl":null,"permalink":"/categories/crowdsec/","section":"Categories","summary":"","title":"CrowdSec","type":"categories"},{"content":"","date":"18 August 2025","externalUrl":null,"permalink":"/series/crowdsec/","section":"Series","summary":"","title":"CrowdSec","type":"series"},{"content":" CrowdSec - современное решение для кибербезопасности, способное защитить ваш сервер от атак, сканеров и брутфорсов. В этом руководстве рассмотрим установку CrowdSec в LXC-контейнере в среде Proxmox VE.\nЕсли вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nВы меня спросите, слушай, stilicho2011, ты же уже одну статью написал. Все так, но, как говорится, есть нюанс. Статья, которую вы можете найти по ссылке, описывает ситуацию, когда мы все устанавливаем в докер.\nСейчас же поговорим ситуации, когда у нас наш обратный прокси установлен в LXC контейнер, о чем я рассказывал тут и тут.\nНо раз мы с вами начали заниматься такими странными вещами, то останавливаться на полпути было бы неправильно. Поэтому если мы с вами установили Traefik в LXC контейнер, то надо нам озаботиться и современной защитой, которую нам предоставляет Crowdsec.\nБезусловно, общий принцип работы Crowdsec остается неизменным вне зависимости от варианта установки, поэтому, в целях сокращения текста, в данной статье я опишу ключевые вещи, которые касаются исключительно особенностей установки Crowdsec в LXC контейнер и его связки с обратным прокси Traefik\nЧто такое CrowdSec? # CrowdSec - это, как было указано выше, современная open-source система безопасности с принципами, схожими с «коллективным фаерволом» (crowdsourced firewall). Она анализирует логи, выявляет подозрительную активность (например, brute-force, сканирование портов, DDoS) и автоматически применяет решения для блокировки или ограничения доступа IP-адресов злоумышленников.\nГлавная особенность CrowdSec - это обмен данными о вредоносных IP-адресах между всеми пользователями системы, с помощью которой создается коллективная база знаний, которая формируется на основе данных всех участников. Таким образом, если один сервер зафиксировал атаку, остальные участники могут заблокировать злоумышленника заранее.\nПоскольку на сайте уже есть более чем подробная статья о функционале приложения, то на всех особенностях Crowdsec я, с вашего позволения, останавливаться не буду.\nНо по законам жанра я обязан рассказать о ключевых архитектурных особенностях Crowdsec\nАрхитектура CrowdSec # CrowdSec построен на модульной архитектуре и глобально разделён на два уровня:\nAgent (движок анализа) - анализирует журналы логов (Nginx, Traefik, SSH, Postfix, системные логи и т.д.).\nBouncers (модули блокировки) - применяют решения о блокировке (ban, captcha, throttle) для защиты или разрешения доступа (например, iptables, Nginx middleware, Traefik bouncer).\nAgent занимается только определением (выявлением) нехороших айпи, а блокировка выполняется с помощью bouncers.\nТаким образом CrowdSec можно легко интегрировать в любую инфраструктуру, не вмешиваясь напрямую в сетевые правила.\nУ нас с вами уже есть установленный и настроенный обратный прокси Traefik в LXC контейнер. В этот же контейнер на базе ОС Debian мы с вами установим Crowdsec. Еще раз повторюсь, - на сайте есть подробная статья о настройке Crowdsec в связке с Traefik в докере.\nУстановка Crowdsec в Linux # Первое, что нам надо сделать, это установить в систему репозиторий Crowdsec. Это можно сделать руками, но это долго и муторно. Поэтому мы воспользуемся официальным скриптом, подготовленным разработчиками Crowdsec. Этот репозиторий содержит последнюю стабильную версию Crowdsec, и это рекомендованный разработчиком способ установки.\ncurl -s https://install.crowdsec.net | sudo sh Проверим, что репозитории установились и система видит версии Crowdsec.\napt list crowdsec Установим Crowdsec неожиданной командой\napt install crowdsec На всякий случай повторюсь, что сам по себе так называемый security engine может только обнаруживать подозрительную/зловредную деятельность, но не банить айпи, которые служат источником такой деятельности.. Поэтому нам надо установить соответствующие bouncers.\nЕсть один немаловажный момент. Если вы все устанавливаете в привилегированный LXC контейнер, то прежде чем настраивать нашу с вами связку и проверять ее работоспособность, нам сначала, недожидаясь перитонитов, нужно установить самостоятельный bouncer для iptables. Этот bouncer будет защищать непосредственно наш LXC контейнер от brute-force атак. Сделаем это командой\napt install crowdsec-firewall-bouncer-iptables Нужно делать, если у вас по каким-то необъяснимым причинам есть желание рисковать и устанавливать что-либо в привилегированный LXC контейнер. В противном случае, устанавливать bouncer для ip tables нет необходимости (но это не точно). И теперь давайте перейдем к окончательной настройке.\nПосле того, как мы установили Crowdsec\nПроверяем статус crowdsec\nsystemctl status crowdsec Создаем белый список адресов, которые Crowdsec не должен проверять. Как правило это частные сети, но, в случае, если у вас есть потребность в более тонкой настройке, то можно точечно вносить доверенные ip адреса.\nСоздаем список командой\nnano /etc/crowdsec/parsers/s02-enrich/01-my-whitelist.yaml и вносим туда соответствующие значения\nname: crowdsecurity/my-whitelists description: \u0026#34;Whitelist events from my ipv4 addresses\u0026#34; #it\u0026#39;s a normal parser, so we can restrict its scope with filter filter: \u0026#34;1 == 1\u0026#34; whitelist: reason: \u0026#34;my ipv4 ranges\u0026#34; ip: - \u0026#34;127.0.0.1\u0026#34; cidr: - \u0026#34;192.168.0.0/16\u0026#34; - \u0026#34;10.0.0.0/8\u0026#34; - \u0026#34;172.16.0.0/12\u0026#34; Таким образом все запросы, которые приходят с частных айпи адресов не будут проверяться crowdsec. Это снимает лишнюю нагрузку с приложения, и исключает варианты, когда crowdsec забанит наши частные айпи из-за того, что частые запросы могут рассматриваться как brute-force атака.\nЧтобы изменения были применены перезагрузим сервис\nsystemctl restart crowdsec Следующим этапом надо подключиться к консоли Crowdsec у них на сайте.\nЭто простая процедура, там все логически понятно.\nПошаговый гайд у Crowdsec на сайте\nЭто нужно для того, чтобы мы могли подключиться к глобальной сети обмена вредоносных айпи. Один из неоспоримых плюсов Crowdsec.\nДа, разработчики будут получать информацию о том, подверглись ли вы атаке. Но это не самая конфиденциальная информация из всех, и с учетом принципов работы Crowdsec, я думаю подключение к консоли стоит того.\nВсе сделали по инструкции: зарегистрировались; выбрали ОС на которой работаете (в нашем случае Linux); получили enrollment key и команду, которую нужно будет ввести в командной строке нашего контейнера; перезагрузили сервис; вернулись на сайт Crowdsec и можем увидеть, что мы можем выбрать 3 бесплатных блоклиста.\nСамое интересное, это конечно информация о crowdsec hub и список коллекций в зависимости от сервиса, который мы хотим защитить.\nДавайте проверим какие коллекции у нас сейчас присутствуют в системе, и проверим значения в acquis.yaml файле, чтобы понять готова ли наша инстанция crowdsec к парсингу логов\nПроверка списка коллекций\ncscli collections list Проверка списка логов, которые парсит Crowdsec\ncscli metrics show acquisition Абсолютно точно там нет коллекций, которые нам нужны. Вот давайте их и установим\nВ этом гайде будем использовать следующие коллекции:\ncrowdsecurity/traefik traefik support: parser and generic http scenarios\ncrowdsecurity/http-cve Detect CVE exploitation in http logs\ncrowdsecurity/base-http-scenarios http common : scanners detection\ncrowdsecurity/sshd support : parser and brute-force detection\ncrowdsecurity/linux core linux support : syslog+geoip+ssh\ncrowdsecurity/appsec-generic-rules A collection of generic attack vectors for additional protection\ncrowdsecurity/appsec-virtual-patching a generic virtual patching collection, suitable for most web servers.\ncrowdsecurity/appsec-crs Appsec: Modsecurity core rule set rules\nУстановим коллекции командой\ncscli collections install crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/base-http-scenarios crowdsecurity/sshd crowdsecurity/linux crowdsecurity/appsec-generic-rules crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-crs Теперь мы должны подсказать Crowdsec как и где парсить локальные логи нашей Линукс машины и логи обратного прокси Traefik. Для этого мы должны отредактировать конфигурационный файл acquis.yaml по соответствующему пути sudo nano /etc/crowdsec/acquis.yaml. Также мы указываем порт по которому у нас будет работать WAF.\nСоздаем примерный файл следующего вида:\nfilenames: - /var/log/traefik/*.log labels: type: traefik --- filenames: - /var/log/syslog - /var/log/auth.log labels: type: syslog --- listen_addr: 0.0.0.0:7422 appsec_config: crowdsecurity/appsec-default name: myAppSecComponent source: appsec labels: type: appsec # #filenames: # - /var/log/authentik.log #labels: # type: authentik #--- #filenames: # - /var/www/nextcloud/data/nextcloud.log #labels: # type: Nextcloud Ради чистоты эксперимента перезагружаем сервис\nsystemctl restart crowdsec Проверка списка логов, которые парсит Crowdsec\ncscli metrics show acquisition Устанавливаем bouncer для нашего обратного прокси Traefik\nЕсли вы следовали моей инструкции по установке Traefik в LXC контейнер, то соответствующий bouncer в виде плагина у вас уже прописан в статической конфигурации обратного прокси, скачан и установлен. Просто он пока еще не знает, что ему делать.\nСначала мы получим соответствущий api ключ, чтобы bouncer мог общаться c Crowdsec\nСделаем это командой\ncscli bouncers add traefik-bouncer Скопируем полученное значение в блокнот. Значения ключа мы увидим только один раз, не забывайте об этом.\nТеперь переходим в динамическую конфигурацию нашего обратного обратного прокси по адресу\nnano /etc/traefik/dynamic/config.yaml Если вы следовали моей статье о настройке Traefik в LXC контейнер, то у вас файл динамической конфигурации имеет примерно следующий вид.\nhttp: # https://doc.traefik.io/traefik/routing/routers/ routers: # harden dashboard access: can only be accessed with a username/password dashboard: entryPoints: - websecure rule: \u0026#34;Host(`traefik-dashboard.domain.ru`)\u0026#34; service: api@internal middlewares: - auth tls: certResolver: cloudflare radarr: entryPoints: - \u0026#34;websecure\u0026#34; rule: \u0026#34;Host(`radarr.domain.ru`)\u0026#34; middlewares: - default-headers - https-redirect tls: certResolver: cloudflare service: radarr # https://doc.traefik.io/traefik/routing/services/ services: radarr: loadBalancer: servers: - url: \u0026#34;http://192.168.x.x:7878\u0026#34; # Change IP Address to your radarr instance passHostHeader: true # https://doc.traefik.io/traefik/middlewares/http/overview/ middlewares: # Middleware for Redirection # This can be used instead of global redirection # auth: basicAuth: users: # users and their MD5 hashed passwords, granted access to the traefik dashboard - \u0026#34;admin:hashedpassword\u0026#34; # openssl passwd -1 \u0026#34;hashedpassword\u0026#34; # https-redirect: redirectScheme: scheme: https permanent: true # default-headers: headers: frameDeny: true browserXssFilter: true contentTypeNosniff: true forceSTSHeader: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 15552000 customFrameOptionsValue: SAMEORIGIN customRequestHeaders: X-Forwarded-Proto: https # crowdsec: plugin: bouncer: enabled: true logLevel: INFO updateIntervalSeconds: 15 updateMaxFailure: 0 defaultDecisionSeconds: 15 httpTimeoutSeconds: 10 crowdsecMode: stream crowdsecAppsecEnabled: true crowdsecAppsecHost: localhost:7422 crowdsecAppsecFailureBlock: true crowdsecAppsecUnreachableBlock: true crowdsecLapiKey: yourlapikey # Replace CrowdSec API key (docker exec crowdsec cscli bouncers add crowdsecBouncer) crowdsecLapiHost: localhost:8080 crowdsecLapiScheme: http forwardedHeadersTrustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 clientTrustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 # https://doc.traefik.io/traefik/https/tls/ tls: options: default: minVersion: VersionTLS12 # change to a lower version if you expect to service Internet traffic from around the world curvePreferences: # below priority sequence can be changed - X25519 # the most commonly used 128-bit - CurveP256 # the next most commonly used 128-bit - CurveP384 # 192-bit - CurveP521 # 256-bit sniStrict: true # true if our own certificates should be enforced cipherSuites: - TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 - TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 - TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 - TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 - TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 # certificates: # - certFile: /etc/traefik/domain.cert # keyFile: /etc/traefik/domain.key # - certFile: /etc/traefik/certificate.pem # keyFile: /etc/traefik/private_key.pem #### Traefik uses its own default certificate for connections without SNI, or without a matching domain. #### However, we can provide our own default certificate, instead of using the Traefik default. # stores: # default: # defaultCertificate: # certFile: /etc/traefik/cert.crt # keyFile: /etc/traefik/cert.key #### Alternatively, we can use an ACME generated default certificate. stores: default: defaultGeneratedCert: resolver: cloudflare domain: main: domain.ru sans: - \u0026#34;*.domain.ru\u0026#34; Как вы видите, мы с вами задали определенные параметры в middleware. При этом, как я указывал выше, вариантов настроек намного, намного больше. Подробнее об этом можно узнать в официальной документации.\nОбязательно внесите в соответствующее поле значения вашего api key, который мы создали ранее.\nТакже обратите внимание, что мы задали значение forwardedHeadersTrustedIPs и clientTrustedIPs. Тем самым мы определяем подсети IPv4 частного класса как доверенные IP-адреса.\nЭто необходимо, поскольку мы хотим доверять HTTP-заголовкам нашего обратного прокси-сервера Traefik, таким как X-Forwarded-For и X-Real-IP. Эти заголовки обычно определяют реальные IP-адреса посетителей нашего сайта, ну и злоумышленников конечно, которые CrowdSec использует для принятия решений и блокировки.\nВы можете сделать более тонкую настройку и добавить точный IP-адрес Traefik в диапазоне /32. Однако добавление всех диапазонов частных классов в белый список - более удобный подход. Особенно это касается динамических IP-адресов подсетей Docker, которые могут меняться при перезагрузке контейнера.\nС помощью переменной clientTrustedIPs мы указываем доверенные IP-адреса или диапазоны IP-адресов, которые мы считаем заслуживающими доверия. Эти IP-адреса или диапазоны сетей не будут заблокированы или запрещены CrowdSec. По сути, это вариант с использованием белого списка, который мы уже создали. В определенной степени у нас тут дублирование задач, но я обязан показать все опции.\nВ моём случае я доверяю локальной сети LAN, что отражается в добавлении всех диапазонов частных классов в белый список. Вы можете ограничить их диапазоном вашей текущей подсети LAN (CIDR) в случае необходимости.\nТак как это динамические настройки Traefik, то нет нужды его перезагружать. Он их подхватит автоматом.\nТеперь, мы можем защищить с помощью Crowdsec наши сервисы выборочно, указывая соответствующую middleware - crowdsec@file в разделе routers нашего обратного прокси, но можно это сделать на глобальном уровне. То есть все входящие запросы на наш обратный прокси будут обработаны Crowdsec. Мне кажется это будет более правильно.\nНапример, файл статической конфигурации Traefik может иметь следующий вид\n# Traefik entrypoints (network ports) configuration entryPoints: web: address: :80 forwardedHeaders: trustedIPs: \u0026amp;trustedIps # Start of Cloudlare\u0026#39;s public IP list - 103.21.244.0/22 - 103.22.200.0/22 - 103.31.4.0/22 - 104.16.0.0/13 - 104.24.0.0/14 - 108.162.192.0/18 - 131.0.72.0/22 - 141.101.64.0/18 - 162.158.0.0/15 - 172.64.0.0/13 - 173.245.48.0/20 - 188.114.96.0/20 - 190.93.240.0/20 - 197.234.240.0/22 - 198.41.128.0/17 - 2400:cb00::/32 - 2606:4700::/32 - 2803:f800::/32 - 2405:b500::/32 - 2405:8100::/32 - 2a06:98c0::/29 - 2c0f:f248::/32 # End of Cloudlare public IP list http: redirections: entryPoint: to: web scheme: https # HTTPS endpoint, with domain wildcard websecure: address: :443 forwardedHeaders: # Reuse the list of Cloudflare\u0026#39;s public IPs from above trustedIPs: *trustedIps http: middlewares: - crowdsec@file # reference to a dynamic middleware for enabling crowdsec bouncer Более подробно вы можете прочитать об этом в статье, которая посвящена настройке Crowdsec в докере, так как я хочу избежать дублирования информации, которая уже есть на сайте.\nТеперь остался вопрос проверки работоспособности нашей схемы.\nКоманда покажет нам метрики нашего Crowdsec. Главное, чтобы Crowdsec парсил логи обратного прокси. В случае если это не так, то перезапустите Traefik и проверьте еще раз\ncscli metrics Давайте теперь забаним наш адрес из частной сети\ncscli decisions add --ip 192.168.x.x Проверим внесли ли нас в бан-лист\ncscli decisions list В списке должен быть указан наш айпи, который мы руками внесли в бан.\nОбратите внимание, что фактически он может быть не забанен, потому что этот айпи у нас еще и в whitelists.\nТеперь разбаним его не дожидаясь 4 часов\ncscli decisions delete --ip 192.168.x.x Проверим результат\ncscli decisions list Нашего айпи в списке забаненных быть не должно.\nВсе - Crowdsec настроен. Но в любом случае я рекомендую почитать статью у меня на сайте про Corwdsec в докере, где более подробно описаны некоторые команды. Как я уже написал выше, в целях избегания дублежа информации я не хочу копировать одно и тоже из статьи в статью.\n","date":"18 August 2025","externalUrl":null,"permalink":"/posts/crowdsec-in-lxc/","section":"Posts","summary":"Подробная инструкция по установке и настройке CrowdSec внутри LXC-контейнера. Рассмотрены ключевые шаги от развертывания до интеграции с защитой сервера и мониторингом активности, чтобы быстро обеспечить безопасность виртуализированного окружения.","title":"Установка и настройка CrowdSec в LXC-контейнере вместе с Traefik","type":"posts"},{"content":"","date":"August 14, 2025","externalUrl":null,"permalink":"/en/tags/postgresql/","section":"Tags","summary":"","title":"Postgresql","type":"tags"},{"content":" Introduction # In my videos about installing various services and applications on a home server, I often use external databases, mostly Postgres. On my Telegram channel someone once asked me why I don\u0026rsquo;t use a single, shared database for all the services that need one, since that\u0026rsquo;s more logical from a resource-efficiency standpoint, easier to manage, and much simpler to back up one database in one container instead of many. That\u0026rsquo;s true. But in my case the reason is pretty mundane. My audience has very different levels of preparation and knowledge. So I have to keep the material accessible, and as you can imagine, telling beginners in every single video \u0026ldquo;here I have an external database, here\u0026rsquo;s how we connect a container to it, go watch other videos about working with external databases\u0026rdquo; would rightfully be seen as annoying. So let\u0026rsquo;s finally start using our resources more sensibly and move all our services to a single PostgreSQL database, and while we\u0026rsquo;re at it, set up pgAdmin - a web interface for managing the database.\nWarning NB!!! I understand that using a PostgreSQL database at home is overkill, even excessive, but a lot of serious applications recommend it as their database of choice (Nextcloud, Authentik, Linkwarden, etc.). So why not?\nNote Disclaimer To keep this simpler, in this article we\u0026rsquo;ll only install PostgreSQL and pgAdmin and connect them. Configuring third-party containers and hooking them up to a shared PostgreSQL database will be covered in a separate article (part 2).\nWhat is PostgreSQL # PostgreSQL is a powerful open-source object-relational database management system (DBMS). It stands out for its reliability, flexibility, and extensibility, which makes it one of the most popular DBMSes in the world.\nHistory # The project started in 1986 at the University of California, Berkeley, under the name POSTGRES. In 1996 SQL support was added and the system got its modern name, PostgreSQL. Today it\u0026rsquo;s developed by a global community of contributors and is actively used both by startups and large corporations. Key features of PostgreSQL # Full SQL compliance\nSupport for the SQL:2011 standard and many extensions. Rich syntax for complex queries. Extensibility\nAbility to add your own data types, functions, and operators. Support for custom extensions, such as PostGIS for geospatial data. Reliability and fault tolerance\nWrite-ahead log (WAL) to protect against data loss. Support for replication and clustering. Performance\nQuery optimization via indexes (B-tree, GiST, GIN, etc.). Support for parallel query execution. Security\nStrong access control system. Encrypted connections (SSL/TLS). JSON support\nAbility to work with both relational and document-oriented data. Where PostgreSQL is used # Web applications - backends built on Django, Ruby on Rails, Laravel, Spring Boot. Analytics systems - BI platforms, reporting. Geographic information systems - via the PostGIS extension. Financial and banking systems - thanks to its reliability and transactional guarantees. PostgreSQL in the development ecosystem # PostgreSQL runs on:\nWindows, Linux, macOS, and BSD. Cloud services (AWS RDS, Google Cloud SQL, Azure Database for PostgreSQL). Docker containers. Advantages of PostgreSQL # Free and open source. The community actively releases updates and fixes. Suitable both for small projects and for high-load systems. When to choose PostgreSQL # When you need a reliable, scalable DBMS. When SQL compatibility and extensibility matter. When the project needs to work with large volumes of data and complex analytical queries. When you need hybrid storage - relational and JSON data in the same database. What is pgAdmin # pgAdmin is the official and most popular PostgreSQL administration tool with a graphical web interface. It lets you work with PostgreSQL without constantly using the command line, which is especially convenient for administrators, developers, and data analysts.\nHistory and purpose # pgAdmin was created as an open-source project to simplify PostgreSQL management. Over the years it has grown into a powerful, full-featured tool that supports both local and remote database administration.\nIts main goal is to provide a convenient way to:\nCreate, edit, and delete databases, tables, and functions. Run SQL queries. Monitor PostgreSQL\u0026rsquo;s status and performance. Configure users, permissions, and roles. Key pgAdmin features # Visual administration interface\nCreate and manage schemas, tables, indexes, and views. Easily configure relationships between tables. SQL editor\nSyntax highlighting. SQL autocompletion. Query history. Monitoring and diagnostics\nView active connections. Analyze query execution (EXPLAIN, EXPLAIN ANALYZE). Charts of load and resource usage. User and security management\nCreate and configure roles. Manage access permissions. Manage security policies. Support for connecting to remote servers\nManage multiple PostgreSQL servers from a single interface. Works with both local and cloud infrastructure. pgAdmin architecture # pgAdmin is a web application that can run:\nLocally - on your own computer.\nIn server mode - accessible via browser from anywhere.\nIn a Docker container - for quick deployment without installing dependencies.\nMain components:\nBackend - written in Python (Flask), handles request processing and interaction with PostgreSQL.\nFrontend - written in JavaScript (React), powers the web interface.\nDatabase storage - stores pgAdmin\u0026rsquo;s settings, the list of servers, and user sessions.\nWhy it\u0026rsquo;s convenient to run pgAdmin in Docker # Fast startup without a complicated install.\nEasy version upgrades (just change the image tag).\nEnvironment isolation - doesn\u0026rsquo;t clutter the host system.\nCan be integrated with PostgreSQL in a single docker-compose.yml.\nWhen to use pgAdmin # When you need to administer PostgreSQL through a convenient web interface.\nTo visualize the database structure and make navigation easier.\nFor performance monitoring and query analysis.\nIf you have multiple PostgreSQL servers and want centralized management.\nWhy we\u0026rsquo;ll install it in Docker # Docker Compose lets us deploy these services quickly and conveniently without installing them directly on the host system.\nIn this guide we\u0026rsquo;ll create a docker-compose.yml to run PostgreSQL and pgAdmin in separate containers. Yes, you could set both up with a single docker-compose file, but since we want to keep the database container isolated from all other containers, we\u0026rsquo;ll split the database and the admin app apart.\nRequirements # Before you start, make sure you have:\nDocker\nIdeally, the database shouldn\u0026rsquo;t just live in its own container, but also be moved off the working machine entirely - for example, hosted on a NAS. This not only protects us from host-related issues, but also lets applications and servers on other machines in the local network connect to it. On top of that, we can confidently wipe and rebuild working machines from scratch, just point them at the path to our database, and everything keeps working as if nothing happened.\nNB!!! It\u0026rsquo;s worth noting that hosting the database on SMB or NFS shares is risky in terms of database corruption. Ideologically, the right place for a database is on an iSCSI volume. But in the video, to keep things simple, I do everything within the same virtual machine. Setting up the PostgreSQL project # Let\u0026rsquo;s create a directory where we\u0026rsquo;ll place our database\nmkdir postgres cd postgres sudo touch docker-compose.yml Now let\u0026rsquo;s create a simple docker-compose file for the database\nI took all the variables from Docker Hub\nservices: postgres: image: postgres:16 # pick whatever version you consider appropriate, but as of August 2025 serious applications still tend to use version 16 container_name: postgres restart: always # set shared memory limit when using docker compose #shm_size: 128mb # or set shared memory limit when deploy via swarm stack #volumes: # - type: tmpfs # target: /dev/shm # tmpfs: # size: 134217728 # 128*2^20 bytes = 128Mb environment: # set the minimum required variables - POSTGRES_PASSWORD=password - POSTGRES_USER=stilicho - POSTGRES_DB=postgres ports: # if all your database-consuming containers will be on the same docker network, you can comment out the ports. Containers will talk to each other by container name inside docker - 5432:5432 volumes: - /home/stilicho/docker/postgres/pgdata:/var/lib/postgresql/data # path on the host where the database will be stored networks: # specify the docker network the database will run on. All containers on the same docker network can communicate by container name database: networks: database: external: true Create a new docker network with the command\ndocker network create database Now let\u0026rsquo;s start our project with docker compose up -d.\nOnce the container has been pulled and started, you\u0026rsquo;ll see a new pgdata folder appear at the path specified in the docker compose file.\nIf you try to open it, you won\u0026rsquo;t see any information. That\u0026rsquo;s normal - it\u0026rsquo;s because the postgres user has its own permissions that the user you\u0026rsquo;re currently working as doesn\u0026rsquo;t have. So if you just want to check that everything\u0026rsquo;s fine and that there\u0026rsquo;s something inside the pgdata folder, use sudo cd pgdata \u0026amp;\u0026amp; sudo ls. Once you see that files and directories have appeared in the pgdata folder, don\u0026rsquo;t touch anything there - we\u0026rsquo;ve just confirmed everything is working.\nSetting up the pgAdmin project # Let\u0026rsquo;s create a directory where we\u0026rsquo;ll place our database\nmkdir pgadmin cd pgadmin sudo touch docker-compose.yml Now let\u0026rsquo;s create a simple docker-compose file for pgAdmin\nI took all the variables from Docker Hub and from the developer\u0026rsquo;s own site for that specific version of the app\nservices: pgadmin: image: dpage/pgadmin4:9.6.0 # the latest version of the app as of when this article was written container_name: pgadmin restart: always environment: # the minimum variables required to start the container - PGADMIN_DEFAULT_EMAIL=user@domain.com - PGADMIN_DEFAULT_PASSWORD=SuperSecret volumes: - /home/stilicho/docker/pgadmin/data:/var/lib/pgadmin # path to the folder where all the app\u0026#39;s data will be stored ports: # container ports. Consider whether you need to close these off if you\u0026#39;re using a reverse proxy. For the purposes of this article I\u0026#39;m leaving them open. - 8080:80 networks: # define the networks pgAdmin will run on. - proxy # the network where my Traefik reverse proxy runs - database # the network where our database runs labels: # standard Traefik reverse-proxy labels for the pgAdmin container, so we can access the web panel via a subdomain over an SSL-secured connection - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.http.routers.pgadmin.entrypoints=http\u0026#34; - \u0026#34;traefik.http.routers.pgadmin.rule=Host(`pgadmin.your_domain.ru`)\u0026#34; - \u0026#34;traefik.http.middlewares.pgadmin-https-redirect.redirectscheme.scheme=https\u0026#34; - \u0026#34;traefik.http.routers.pgadmin.middlewares=pgadmin-https-redirect\u0026#34; - \u0026#34;traefik.http.routers.pgadmin-secure.entrypoints=https\u0026#34; - \u0026#34;traefik.http.routers.pgadmin-secure.rule=Host(`pgadmin.your_domain.ru`)\u0026#34; - \u0026#34;traefik.http.routers.pgadmin-secure.tls=true\u0026#34; - \u0026#34;traefik.http.routers.pgadmin-secure.service=pgadmin\u0026#34; - \u0026#34;traefik.http.services.pgadmin.loadbalancer.server.port=80\u0026#34; - \u0026#34;traefik.docker.network=proxy\u0026#34; networks: database: external: true proxy: external: true But before starting the container, we need to manually create the directory where pgAdmin\u0026rsquo;s data will live and set the correct permissions on it. This is a mandatory step.\nSet the permissions with a simple command\nsudo chown -R 5050:5050 \u0026lt;host_directory\u0026gt;` # userid and groupid taken from the official documentation. Now we can start the pgAdmin docker compose file\ndocker compose up -d The container will download and start fairly quickly.\nNow, depending on how you\u0026rsquo;re running your container, you can access it at your_ip_address:8080, or, in my case, at the subdomain pgadmin.your_domain.ru\nWe land on the welcome screen\nEnter the login and password we set in the docker compose file\nWe land in pgAdmin\u0026rsquo;s standard welcome screen\nSince this article has already gotten quite long, let\u0026rsquo;s wrap up the initial setup with two mandatory things.\nLet\u0026rsquo;s enable dark mode\nGo to Files \u0026gt; Preferences \u0026gt; Miscellaneous \u0026gt; User Interface and select the dark theme.\nNow that the visuals are sorted, let\u0026rsquo;s connect to our database\nRight-click on the servers section in the pgAdmin browser. Choose register, then click Server.\nIn the window that appears, on the General tab, give your server a name\nGo to the Connection tab and enter the address where our database is reachable. If it\u0026rsquo;s on the same docker network, the container name alone will be enough - docker handles the rest of the magic for you.\nIn the login field your login is already filled in, taken from the values you specified in the docker compose file, and in the password field you need to enter the database password specified in the database\u0026rsquo;s docker compose file\nYou can toggle the \u0026ldquo;save password\u0026rdquo; switch so you don\u0026rsquo;t have to enter it every time.\nNow, if everything\u0026rsquo;s in order, you\u0026rsquo;ll see our Postgres database show up under the server section\nWe now have full access to our database and are ready to deploy the services that will use the shared database. For how to properly create a separate user and database for a specific application and connect it to the shared PostgreSQL, see part two.\nIf you enjoyed this article and found it useful, you can become a sponsor on Boosty via the link in the contacts.\n","date":"August 14, 2025","externalUrl":null,"permalink":"/en/posts/postgres-p-1/","section":"Posts","summary":"A detailed guide to installing and configuring PostgreSQL on a server. Covers installation steps, creating users and databases, setting up backups, and basic security for stable and reliable operation.","title":"Setting up PostgreSQL and pgAdmin in Docker with Docker Compose for beginners. Part 1","type":"posts"},{"content":"Этой статьей я продолжаю тему по автоматизации установки и настройки нашей инфраструктуры с помощью Proxmox. Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nРанее я рассказывал как можно создавать шаблоны в Proxmox - это \u0026ldquo;слепок\u0026rdquo; состояния виртуальной машины или LXC-контейнера на нужный нам момент времени, из которого мы потом можем \u0026ldquo;разворачивать\u0026rdquo; копии машин; и как создавать вируальные машины с помощью cloud-init. Теперь воспользуемся этими тайными знаниями и пойдем по пути автоматизации развертывания нашей инфраструктуры еще дальше и начнем использовать Terraform.\nЗачем автоматизировать создание виртуальных машин в принципе? # Ручное создание ВМ в Proxmox удобно на начальном этапе, но с ростом количества инстансов процесс становится трудоёмким, а соответственно подверженным ошибкам. Более того, ну одну, две вм мы еще развернем, не развалимся. А что если нужно одновременно развернуть \u0026gt; 5 виртуальных машин?\nЗачем автоматизировать создание виртуальных машин дома? # То, что вы создаёте, должно поддерживаться. Ведь всю вашу, с таким трудом созданную, инфрастуктуру легко развалить или даже сломать, если не уделять вопросу поддержки или обслуживания должного внимания.\nВы потратили бесчисленные часы на построение своей инфраструктуры, выверяя каждую деталь, читая много статьей, мануалов, просмотрели кучу ютуб роликов разной степени полезности. Но что случится, если что-то пойдёт не так, и вам придётся всё восстанавливать с нуля? Что если весь ваш тяжёлый труд просто исчезнет по мановению случайного Ctrl+Alt+Del?\nТема настоящей статьи # В этой статье и видео в начале статьи я покажу вам, как настроить Terraform для обслуживания вашей инфраструктуры так, чтобы вам никогда не пришлось всё пересобирать заново с нуля, роясь в своих записях (если вы их ведете), или роясь в самых потаенных уголках своей памяти (если она у вас работает) в попытке восстановить последовательность ваших действий.\nБудь то небольшое изменение конфигурации или управление целыми виртуальными машинами - Terraform поможет вам всё держать под контролем.\nИспользование Terraform позволяет описать конфигурацию вашей инфраструктуры как код (IaC), благодаря чему вы можете:\nСоздавать ВМ с одинаковыми параметрами за секунды. Версионировать инфраструктуру. Интегрировать развертывание в CI/CD. Повысить воспроизводимость и предсказуемость среды. На всякий случай поясню, что инфраструктура как код - это когда мы с вами описываем аппаратную часть нашей системы в текстовом формате. Не путайте с Ansible, где принцип такой же, но там мы описываем программную среду.\nЧто такое Terraform? # Terraform – это инструмент от компании Hashicorp, помогающий декларативно управлять инфраструктурой с помощью соответствующих конфигурационных файлов. Это значит - нам не надо вручную создавать виртуальные машины, сети и т.д. Достаточно написать конфигурацию, в которой будет изложено, как вы видите вашу будущую инфраструктуру. Такая конфигурация создается в текстовом формате yaml. Соответственно изменения в нашу инфраструктуру тоже вносятся с помощью правок текстового файла. Новичкам - может показаться сложно и непонятно по началу, но когда втянетесь, вы поймете всю прелесть хранения всей вашей инфраструктуры в паре текстовых файлов. Вы же понимаете прелесть описания вашего софта в docker-compose файле? Вот и тут почти также. При этом Terraform поддерживает множество платформ, включая Proxmox VE.\nУчтите, что в настоящий момент для доступа к сайту Terraform может потребоваться соответствующая технология, так как они от нас закрылись.\nВарианты установки Terraform # Как установить Terraform в Docker\nTerraform может быть установлен несколькими способами, условно разделю их на два варианта: нативно и с помощью Docker. Я буду описывать установку с помощью Docker. Почему?\nОба способа установки Terraform - нативно и с помощью Docker - имеют свои плюсы и минусы. Выбор зависит от целей, окружения и предпочтений. Давайте посмотрим на плюсы и минусы, как это вижу я. Кстати, если не согласны, пишите в комментариях под роликом. Я надеюсь, что вы понимаете, - все плюсы и минусы это достаточно условно?\nНативная установка Terraform # Плюсы # Простой и прямой доступ: можно вызывать terraform напрямую из терминала. Интеграция с другими инструментами CLI: Ansible, Packer и пр. Поддержка IDE: автокомплит, подсветка синтаксиса и плагины в VS Code и других редакторах. Удобное редактирование и тестирование локально. Быстрее запускается, чем через Docker. Минусы # Требует ручного контроля версий. Высока вероятность проблем в работе с провайдером о которых чуть позже. Возможны конфликты между проектами с разными версиями Terraform. Нужно устанавливать и обновлять вручную. Кому может подойти # Оптимально для локальной разработки, частой работы с инфраструктурой и гибкой настройки.\nУстановка Terraform с помощью Docker # Плюсы # Не требует установки Terraform на хост. Легко переключаться между версиями с помощью тегов Docker-образа. Идеально для CI/CD пайплайнов (GitHub Actions, GitLab CI и пр.). Изоляция окружения - никакого конфликта зависимостей. Минусы # Менее удобно для интерактивной работы. Требуется пробрасывать volume и прописывать пути вручную (-v $(pwd):/workspace). Медленнее запуск по сравнению с нативной установкой. Не работает напрямую с локальным SSH-агентом, переменными окружения без явного проброса. Кому может подойти # Идеально подходит для автоматизации, CI/CD и одноразовых сценариев, когда важна изоляция среды. Для дома хорошо подходит.\nВыводы # Сценарий Рекомендованный подход Локальная разработка, частое взаимодействие Нативно Автоматизация и CI/CD Docker Работа с несколькими версиями Terraform Docker Гибкость и глубокая интеграция с системой Нативно Обратите внимание В видео ролике я использую VS Code, как более простой инструмент. Я предполагаю, что у вас уже настроена виртуальная машина в Proxmox и установлен docker, а также подготовлен шаблон виртуальной машины на Ubuntu в Proxmox VE, как мы это с вами делали в предыдущей статье. Установка Terraform # Создаем директорию и назовем ее terraform, чтобы не запутаться\nШаг 1: Создание структуры проекта # mkdir terraform cd terraform Создайте файл docker-compose.yml со следующим содержимым:\nservices: terraform: image: hashicorp/terraform:latest #Официальный образ terraform volumes: - .:/terraform # маппим тома. Точка показывает, что установка будет в директорию terraform, в который мы с вами сейчас находимся working_dir: /terraform # Описываем рабочую директорию. Она должна совпадать с той, что задана строчкой выше. В противном случае terraform обидится и не будет работать network_mode: host # обязательно указываем тип сети как хост. Это нужно для того, что terraform мог взаимодействовать с proxmox и нам не нужно будет делать дополнительные настройки сети, которые понимают не только лишь все Шаг 2: Установка расширения Terraform в VS Code # Откройте VS Code → Extensions → найдите Terraform → Установите. Это расширение поможет нам взаимодействовать с Terraform, интерпретируя язык Terraform в понятную нам структуру и формат. Я пользуюсь официальным плагином от Hashicorp - разработчик Terraform\nШаг 3: Создаем файл с учётными данными # Формально учетные данные мы могли бы указать и в файле provider.tf (о нем чуть позже), но формально это неправильно с точки зрения безопасности. Поэтому давайте хотя бы здесь постараюсь показать правильно.\nСоздайте файл в нашей директории командой :\ntouch credentials.auto.tfvars # tf.vars означает переменные (variables) terraform Пример содержимого credentials.auto.tfvars:\nproxmox_api_url = \u0026#34;https://\u0026lt;ВАШ_IP\u0026gt;:8006/api2/json\u0026#34; proxmox_api_token_id = \u0026#34;root@pam!terraform\u0026#34; proxmox_api_token_secret = \u0026#34;\u0026lt;ВАШ_СЕКРЕТ\u0026gt;\u0026#34; # proxmox показывает его один раз, поэтому сразу скопируйте Правильно создавать конечно отдельного юзера в Proxmox и задать ему сначала соответствующие права. Но я хочу для целей этой статьи сделать все максимально просто, поэтому я буду использовать пользователя root. С точки зрения безопасности - это неправильно! Создайте токен в Proxmox:\nDatacenter → Permissions → API Tokens → Add Пользователь: root@pam Token ID: terraform Снимите галочку с “Privilege Separation” Шаг 4: Провайдер (provider.tf) # Сначала давайте определимся, что такое provider. Provider в нашем случае - это некий бридж между Terraform и вашей платформой, на которой вы разворачиваете Terraform. В нашем случае - это Proxmox VE, но в продакшене это может быть любая серьезная облачная инфраструктура типа AWS, Azure и т.д. При этом для каждой платформы свой провайдер.\nМы будем использовать провайдера от Telmate. Связано это с тем, что официального провайдера для Proxmox от разработчиков нет. И тут есть один хитрый момент. У этого провайдера есть проблемы с версионностью. То есть не каждая версия провайдера заведется с разными версиями Proxmox VE. В интернете по этому поводу всегда много стонов. Очень похожая ситуация с Nextcloud - всем нужен, все плачут, но продолжают использовать.\nNote Актуализация. На момент написания статьи Telmate был самым очевидным выбором, но с тех пор ситуация в сообществе поменялась: провайдер bpg/proxmox стал активнее развиваться и умеет заметно больше - помимо VM/LXC он управляет пользователями, ролями, firewall, SDN и т.д., то есть почти всем, о чём я писал в статьях про Proxmox. Если вы начинаете новый проект с нуля - присмотритесь и к нему. Но раз уж этот гайд построен вокруг Telmate, и он по-прежнему рабочий (просто более ограниченный по функциям), я оставляю его как есть - логика с провайдерами в Terraform у обоих вариантов одинаковая, поменяется в основном source и набор аргументов.\nОткрываем Terraform Registry → ищем terraform proxmox → выбираем ссылку от Telmate. Я выбрал его, потому что он широко используется, а поэтому его легче \u0026ldquo;дебажить\u0026rdquo;.\nНажимаем \u0026ldquo;Use Provider\u0026rdquo; и копируем предложенный код в наш файл для данных провайдера.\nПосле заполнения скопированной части файла, - ниже, на той же странице провайдера будут переменные, которые я использую в конфигурационном файле.\nСодержимое:\nterraform { required_providers { proxmox = { source = \u0026#34;Telmate/proxmox\u0026#34; version = \u0026#34;3.0.2-rc03\u0026#34; } } } provider \u0026#34;proxmox\u0026#34; { pm_api_url = var.proxmox_api_url pm_api_token_id = var.proxmox_api_token_id pm_api_token_secret = var.proxmox_api_token_secret pm_tls_insecure = true } variable \u0026#34;proxmox_api_url\u0026#34; { type = string description = \u0026#34;URL API Proxmox, например https://proxmox.example.com:8006/api2/json\u0026#34; } variable \u0026#34;proxmox_api_token_id\u0026#34; { type = string description = \u0026#34;API token id в формате user@realm!tokenid, например root@pam!terraform\u0026#34; } variable \u0026#34;proxmox_api_token_secret\u0026#34; { type = string description = \u0026#34;Секретный ключ API токена\u0026#34; sensitive = true } С этой частью закончили, переходим к инициализации всего того что мы только что с вами натворили.\nШаг 5: Инициализация Terraform # В терминале переходим в директорию где у нас находятся наши файлы.\nВводим следующую команду\ndocker compose -f docker-compose.yml run --rm terraform init Сейчас поясню, что это значит.\nВ своих роликах я никогда не запускал докер с флагом -f, но тут особый случай.\nФлаг -f определяет какой конкретно файл надо запустить. В нашем случае docker-compose.yml. Команда \u0026ndash;rm говорит, что контейнер должен самоликвидироваться, после того, как он выполнит свои темные делишки. Запускаем команду. После того как контейнер будут скачан, наш проект будет запущен. То есть скачивается контейнер Terraform, скачивается провайдер, устанавливаются все необходимые бекэнд файлы. В итоге мы должны получить сообщение, что Terraform инициализирован. В нашей директории Terraform мы увидим новые файлы. Трогать их нам не надо, но просто само их наличие говорит о том, что все в порядке. Так и должно быть. Фактически Terraform проверяет возможность соединения с ProxmoxVE\nВ версии Proxmox 9.0.3 вы получите ошибку, которая нам скажет, что Terraform понятия не имеет, что это за провайдер такой Telmate, откуда брать его данные и т.д. Решить это можно только путем ручного скачивания бинарного файла нашего провайдера и прописывания соответствующих путей в docker-compose файле.\nСделаем с вами следующее\nsudo mkdir -p ~/.terraform.d/plugins/registry.terraform.io/telmate/proxmox/3.0.2-rc03/linux_amd64 #создаем директорию для плагина wget https://github.com/Telmate/terraform-provider-proxmox/releases/download/v3.0.2-rc03/terraform-provider-proxmox_3.0.2-rc03_linux_amd64.zip #скачиваем нужную версию плагина sudo unzip terraform-provider-proxmox_3.0.2-rc03_linux_amd64.zip -d ~/.terraform.d/plugins/registry.terraform.io/telmate/proxmox/3.0.2-rc03/linux_amd64 #разархивируем плагин и переместим его во вновь созданную директорию После того как мы все с вами скачали, разархивировали и переместили в нужную директорию, надо внести изменения в наш docker compose файл\nservices: terraform: image: hashicorp/terraform:latest volumes: - .:/terraform - ~/.terraform.d/plugins/registry.terraform.io/telmate/proxmox/3.0.2-rc03/linux_amd64:/root/.terraform.d/plugins/registry.terraform.io/telmate/proxmox/3.0.2-rc03/linux_amd64:ro working_dir: /terraform network_mode: host Тут мы руками прописываем путь, по которому надо смотреть/искать нашего провайдера.\nОпять вводим команду\ndocker compose -f docker-compose.yml run --rm terraform init В этот раз у нас все должно быть хорошо и проект должен пройти инициализацию\nШаг 6: Проверка текущего состояния # Запускаем следующую команду.\ndocker compose -f docker-compose.yml run --rm terraform plan Как вы видите, команда не особо отличается от предыдущей, кроме последнего значения. Эта команда нужна, чтобы проверить, какие именно изменения будут применены, но без фактического их применения. Этакий тестовый прогон. Поэтому если на этом этапе что-то пошло не так, то дальше нам надо понять где и что пошло не так. Но никакие изменения в работающую инфраструктуру не вносятся. Пока мы ничего не конфигурировали, никаких изменений не применяли, поэтому Terraform просто скажет, что всё актуально. Это нормально реакция.\nНо в версии Proxmox 9.0.3/4 по состоянию на дату написания статьи у вас опять выскочит ошибка. Ошибка будет связана с \u0026ldquo;якобы\u0026rdquo; недостаточным объемом прав у токена. Это на самом деле не так. Дело в том, что в Proxmox 9 убрали привилегию VM.Monitor, заменив её на VM.GuestAgent.Audit, а провайдер Telmate версии 3.0.2-rc03 на момент написания статьи об этом ещё не знал и продолжал требовать несуществующую привилегию. Мы же токен от пользователя root создавали, у нас прав выше крыши. Чтобы избавиться от этой ошибки внесем изменения в файл provider.tf.\nNote Актуализация. Начиная с версии провайдера 3.0.2-rc04 этот баг официально пофикшен - разработчики убрали VM.Monitor из списка обязательных привилегий для Proxmox 9. На момент актуализации статьи (август 2026) актуальная версия провайдера - 3.0.2-rc09. Так что если вы читаете это сейчас, обновите version в блоке required_providers на актуальную версию с Terraform Registry - и pm_minimum_permission_check = false вам, скорее всего, вообще не понадобится. Ниже я всё равно оставляю этот флаг как рабочий обходной путь - он не сломает конфигурацию, даже если баг у вас уже пофикшен.\nterraform { required_providers { proxmox = { source = \u0026#34;Telmate/proxmox\u0026#34; version = \u0026#34;3.0.2-rc03\u0026#34; } } } provider \u0026#34;proxmox\u0026#34; { pm_api_url = var.proxmox_api_url pm_api_token_id = var.proxmox_api_token_id pm_api_token_secret = var.proxmox_api_token_secret pm_tls_insecure = true pm_minimum_permission_check = false # отключем проверку прав } variable \u0026#34;proxmox_api_url\u0026#34; { type = string description = \u0026#34;URL API Proxmox, например https://proxmox.example.com:8006/api2/json\u0026#34; } variable \u0026#34;proxmox_api_token_id\u0026#34; { type = string description = \u0026#34;API token id в формате user@realm!tokenid, например root@pam!terraform\u0026#34; } variable \u0026#34;proxmox_api_token_secret\u0026#34; { type = string description = \u0026#34;Секретный ключ API токена\u0026#34; sensitive = true } Мы укажем новую переменную pm_minimum_permission_check = false, которая отключает проверку прав. На дату написания статьи - это был единственный рабочий вариант\nТеперь, когда мы с вами введем еще раз команду\ndocker compose -f docker-compose.yml run --rm terraform plan то мы увидим что конфигурация применена. На самом деле никакой конфигурации мы еще не сформировали,- это просто проверка работоспособности на будущее\nШаг 7: Создание первой виртуальной машины (youtubetest.tf) # Давайте заставим Terraform создать первую виртуальную машину на Ubuntu из нашего предварительно созданного шаблона. Как создать шаблон у меня есть статья на сайте и видео на канале. И даже есть плейлист с названием автоматизация в Proxmox. Пора уже заняться всем по взрослому.\nПрежде всего опять зайдем на сайт Telmate и подсмотрим там нужные нам переменные в разделе proxmox_vm_qemu.\nСоздаем соответствующий файл с названием youtubetest.tf. Именно в нем мы будем задавать значения для нашей виртуальной машины, которую мы будем создавать с помощью Terraform.\ntouch youtubetest.tf Пример содержимого:\nresource \u0026#34;proxmox_vm_qemu\u0026#34; \u0026#34;youtubetest\u0026#34; { vmid = 357 #id создаваемой машины name = \u0026#34;youtubetest\u0026#34; # ее название target_node = \u0026#34;belisarius\u0026#34; # название ноды clone = \u0026#34;ubuntutemplate\u0026#34; # название шаблона из которого все разворачиваем full_clone = true bios = \u0026#34;ovmf\u0026#34; agent = 1 # установить qemu-guest-agent scsihw = \u0026#34;virtio-scsi-single\u0026#34; os_type = \u0026#34;ubuntu\u0026#34; cpu_type = \u0026#34;x86-64-v2-AES\u0026#34; cores = 2 sockets = 1 memory = 2048 disks { scsi { scsi0 { disk { size = \u0026#34;32G\u0026#34; storage = \u0026#34;local\u0026#34; format = \u0026#34;qcow2\u0026#34; } } } } network { id = 0 model = \u0026#34;virtio\u0026#34; bridge = \u0026#34;vmbr0\u0026#34; } } Это мы с вами создаем нашу первую, самую простенькую, виртуальную машину с помощью текстового файла.\nТеперь давайте еще раз применим уже известную нам команду\ndocker compose -f docker-compose.yml run --rm terraform plan Соответственно Terraform должен показать все изменения, которые он должен применить.\nШаг 8: Применение конфигурации # Давайте теперь уже начнем разворачивать нашу виртуальную машину в реальности.\ndocker compose -f docker-compose.yml run --rm terraform apply Нужно будет подтвердить наше потайное желание начать создание виртуальной машины вводом команды:\nyes Теперь начнётся клонирование ВМ в Proxmox, статус будет виден в логах ProxmoxVE. После завершения ВМ автоматически запустится.\nВ Summary вы увидите IP - благодаря guest-agent.\nМожно открыть консоль - ВМ загружена и готова.\nШаг 9: Тест восстановления # Давайте теперь проверим как у нас работает процесс восстановления. Так как мы с вами все сделали с помощью Terraform, то вот пусть теперь он сам за поддержку нашей инфраструктуры и отвечает.\nУдалим ВМ вручную в ProxmoxVE, затем опять запустим уже известную нам команду :\ndocker compose -f docker-compose.yml run --rm terraform apply Шаг 10: Обновление конфигурации # Давайте изменим нашу конфигурацию ВМ, например:\nmemory = 8192 cores = 2 Повторно примените:\ndocker compose -f docker-compose.yml run --rm terraform apply Пару секунд и вуаля, у нас все обновилось.\nЕсли эта статья вам помогла, то можете подписаться на мой ютуб канал и стать спонсором на boosty.\n","date":"12 August 2025","externalUrl":null,"permalink":"/posts/terraform-proxmox-vm-automation/","section":"Posts","summary":"Пошаговое руководство по автоматической установке виртуальных машин в Proxmox 9.0.3 с использованием Terraform в Docker. Рассмотрены настройка окружения, создание конфигураций Terraform и автоматизация развертывания VM для ускорения и упрощения работы с Proxmox.","title":"Автоматическая установка виртуальной машины в Proxmox 9.0.3 с помощью Terraform в Docker","type":"posts"},{"content":"If you enjoyed this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\nOn my YouTube channel and website there\u0026rsquo;s a whole series of articles and videos about IAM solutions: Authentik, Authelia, Keycloak, and Zitadel. In all of them, one way or another, the same three terms keep coming up - TOTP, WebAuthn, and Passwordless Login - as methods of logging in and as a second factor of protection. But I\u0026rsquo;ve never once come across a clear explanation of how they actually differ from each other, beyond \u0026ldquo;it\u0026rsquo;s also two-factor auth.\u0026rdquo; I decided to close this gap with one article, so I can simply link to it from the others going forward.\nWhy bother understanding this at all # A password as the sole method of login is something that has proven its inadequacy many times over: passwords get reused, they leak in database breaches, they get phished through fake login forms. The industry has been actively moving toward something more reliable for about a decade now, and today even people far removed from IT run into this in one form or another - if only through logging into a government portal with a code from an app, or via Face ID on their phone.\nNext I\u0026rsquo;ll break down TOTP, WebAuthn, and Passwordless Login individually, and at the end - how WebAuthn and the passwordless approach relate to each other, because that\u0026rsquo;s usually where the confusion happens.\n1. TOTP - time-based one-time codes # TOTP (Time-based One-Time Password) is a two-factor authentication method in which a one-time code is generated based on the current time and a shared secret key. It\u0026rsquo;s the oldest and most familiar of the three options - that same six-digit code in Google Authenticator, Authy, Bitwarden, or Vaultwarden (I use the latter myself).\nHow it works in practice: when linking an account, the service shows a QR code, the app scans it and receives the secret key. From then on, both the service and the app independently compute the same code every 30 seconds based on that key and the current time - which is why it\u0026rsquo;s important for the phone\u0026rsquo;s clock to be in sync. The user simply enters the current code in addition to their password.\nStrengths:\nHuge maturity and compatibility - TOTP is supported by practically any service with two-factor auth, from banks to homegrown self-hosted panels. Doesn\u0026rsquo;t require an internet connection at the moment of login - the code is computed locally on the device. Noticeably strengthens a regular password at almost no implementation cost. Weaknesses:\nTOTP is an addition to a password, not a replacement for it. The password still has to be strong: if it\u0026rsquo;s stolen, the TOTP code is the only thing standing between an attacker and your account. Vulnerable to real-time phishing: if a victim is lured to a fake login page and enters both the password and the current TOTP code there, the attacker can immediately relay both values to the real site. This requires an active \u0026ldquo;in the moment\u0026rdquo; attack rather than a leaked database - an unpleasant but not the most widespread scenario. 2. WebAuthn - authentication using cryptography # WebAuthn (Web Authentication API) is an open standard from the W3C and FIDO Alliance that allows logging into a service using a cryptographic key pair instead of a password or code.\nHow it works: during registration, the device generates a key pair - the private key stays on the device (in a secure chip, TPM, or Secure Enclave) and is never transmitted anywhere; the public key is sent to the server and stored in your profile. On every login, the server sends a random \u0026ldquo;challenge,\u0026rdquo; the device signs it with the private key, and the server verifies the signature with the public key. A password plays no role in this scheme at all.\nPractical implementations of WebAuthn include hardware security keys (YubiKey, SoloKey), built-in biometrics (fingerprint, Face ID, Windows Hello), and the device\u0026rsquo;s own secure modules.\nStrengths:\nResistant to phishing in principle, not just \u0026ldquo;mostly\u0026rdquo;: the signature is cryptographically bound to the site\u0026rsquo;s domain, so even a perfect copy of the login page can\u0026rsquo;t obtain a working signature for the real server. No password - nothing to intercept, nothing to leak when the service\u0026rsquo;s database is breached. Good out-of-the-box support for biometrics and hardware tokens in modern browsers and OSes. Weaknesses:\nRequires support both from the browser and from the specific site - for old or homegrown internal systems, this can be non-trivial to bolt on. Transferring keys between devices has historically been a pain point (more on this below, in the section on passkeys). Hardware keys like YubiKey aren\u0026rsquo;t the cheapest thing, and I strongly recommend keeping a backup key in case the primary one is lost or breaks - otherwise you risk losing access to your own accounts. So what are passkeys? # Passkeys deserve a separate mention - this isn\u0026rsquo;t a separate technology, but a marketing name for a specific, \u0026ldquo;convenient\u0026rdquo; way of using WebAuthn, which Apple, Google, and Microsoft have been actively pushing for the past couple of years. The key difference between a passkey and a classic hardware WebAuthn key is synchronization: the private key isn\u0026rsquo;t stored on just one device, but is synced in encrypted form across the cloud (iCloud Keychain, Google Password Manager, and similar) between all of a user\u0026rsquo;s devices. This solves the main pain point of early WebAuthn versions - \u0026ldquo;I linked a YubiKey, and now I have a new phone and I\u0026rsquo;m panicking\u0026rdquo; - but it deliberately sacrifices a bit of the threat model in favor of convenience, since the private key now technically leaves a specific piece of hardware. For most people this is a reasonable trade-off; for the paranoid, it\u0026rsquo;s a reason to stick with unsynced hardware keys.\n3. Passwordless Login - logging in without a password # Passwordless Login isn\u0026rsquo;t a specific technology but a general approach: no password is used for login at all, and instead you use one of the following:\nvia e-mail - the service sends a one-time link (magic link); via SMS or messenger - a confirmation code arrives on your phone; via WebAuthn/passkey - cryptographic login without a password (personally I use either Vaultwarden or Windows Hello, depending on the device); via OAuth - login through an existing Google, GitHub, Microsoft, etc. account. Strengths:\nNo password - nothing to forget, nothing to reuse on other sites, nothing to leak when a database is compromised. Noticeably simplifies the login process for the user - sometimes literally one click. Can act both as the primary login method and as an additional factor. Weaknesses:\nIf the option relies on email or SMS, the security of the login depends entirely on the security of that third-party channel - and SMS has long and deservedly been considered the weakest link (interception via SIM-swap is a real and well-documented threat). I\u0026rsquo;d recommend not relying on SMS as the sole login method anywhere security matters. Since there\u0026rsquo;s no password, account protection effectively shifts entirely onto the protection of the login channel itself (email, phone number, device) - which accordingly requires no less, and sometimes even more, attention to security. 4. What\u0026rsquo;s the difference between WebAuthn and Passwordless Login # This is usually where confusion arises most, because the terms are used side by side and about the same thing - but they\u0026rsquo;re actually different levels of abstraction.\nWebAuthn is a specific, modern, and cryptographically robust protocol/API - one of the tools in the toolkit. Passwordless Login is a goal or strategy (\u0026ldquo;let\u0026rsquo;s get rid of the password altogether\u0026rdquo;), which can be implemented via WebAuthn, or via far less reliable magic links to email or SMS codes. In other words: any login via WebAuthn is passwordless by definition, but not every passwordless login is equally secure, because WebAuthn is a far cry from a one-time email link in terms of phishing resistance.\nComparison of WebAuthn and Passwordless Login in general # Characteristic WebAuthn Passwordless Login (in general) What it is A standard and API for authentication using cryptography A general approach to password-free login, by any means Technology base Asymmetric cryptography (key pair) Can be anything: WebAuthn, email links, one-time codes, biometrics Examples YubiKey, passkeys, Windows Hello, Face ID, TPM Magic link via email, SMS code, push notification, WebAuthn Phishing resistance Very high - the private key never leaves the controlled trust chain Heavily depends on the method: SMS/email are noticeably weaker, WebAuthn/biometrics are at the level of best practices Convenience Fast, no typing required, but needs a supported device Often even simpler (one click on a link), but sometimes slower due to waiting for an email/SMS Infrastructure requirements The server must implement the FIDO2/WebAuthn API Can be simpler: an SMTP or SMS gateway is enough Suitable as 2FA Yes Yes, but not always - depends on the specific method 5. Summary table for all three # Technology Uses a password? Time-dependent? Phishing resistant? Typical example TOTP Yes, as a supplement Yes No Google Authenticator, Vaultwarden WebAuthn No No Yes YubiKey, passkey, Touch ID Passwordless No Depends on the method Depends on the method Magic link, SMS code, WebAuthn 6. How to choose in practice # From my experience setting up Authentik, Authelia, Keycloak, and Zitadel in my own homelab, I\u0026rsquo;d suggest the following:\nYou just need a second factor for an existing password, as compatible as possible and with no extra cost - go with TOTP; it will work almost everywhere and won\u0026rsquo;t require new hardware. Maximum phishing protection matters and you\u0026rsquo;re willing to spend once on a hardware key (or can manage with the device\u0026rsquo;s built-in biometrics) - WebAuthn, without question, ideally as a passkey so you\u0026rsquo;re not stuck being tied to a single device. You want to get rid of passwords entirely as a risk category - build passwordless login on top of WebAuthn/passkey, and use magic links to email or SMS as a fallback rather than the primary path. In practice, these three approaches combine beautifully: for me, for example, password + TOTP covers the base level of services, while anything exposed externally and especially critical is additionally protected by a WebAuthn key through the same Authentik.\nConclusions # TOTP strengthens a regular password with a one-time code - the most compatible and simplest option to implement, but not protected against real-time phishing.\nWebAuthn is a cryptographically robust password-free login protocol, resistant to phishing by its very nature; passkeys are its modern implementation, synced across devices.\nPasswordless Login is a general strategy of moving away from passwords, which can rely on WebAuthn (in which case it\u0026rsquo;s genuinely reliable) or on much weaker magic links and SMS codes (in which case login security is determined by the security of that channel).\nUseful links:\nWebAuthn Guide FIDO Alliance RFC 6238 - TOTP ","date":"August 10, 2025","externalUrl":null,"permalink":"/en/posts/totp-webauthn-passwordless/","section":"Posts","summary":"A detailed look at TOTP, WebAuthn, passkeys, and Passwordless Login: how they work, their strengths and weaknesses, and recommendations for choosing the right technology for logging into your services.","title":"TOTP vs WebAuthn vs Passwordless - what's the difference and which one to choose","type":"posts"},{"content":"Authelia is a modern solution for access management and two-factor authentication that\u0026rsquo;s easy to deploy in a Docker environment. In this guide we\u0026rsquo;ll cover what Authelia is, how to install it, and how it differs from other SSO (Single Sign-On) solutions - for a detailed comparison of Authelia with Authentik, Keycloak, and ZITADEL, see the separate article.\n--- What is Authelia? # Authelia is an open platform for authentication and authorization, designed to protect web applications deployed behind a reverse proxy (such as Traefik or NGINX).\nKey features of Authelia # Protecting any web applications by domain or URI Support for 2FA (TOTP, Duo, WebAuthn, etc.) Integration with LDAP, Active Directory, or files Compatibility with Traefik, NGINX, Caddy A full-fledged SSO mechanism Support for ACL (rule-based access permissions) How does Authelia differ from other solutions? # Characteristic Authelia Authentik Keycloak ZITADEL Ease of installation ⭐⭐⭐⭐ ⭐⭐⭐ ⭐ ⭐⭐ 2FA support ✅ ✅ ✅ ✅ SSO support ✅ ✅ ✅ ✅ Open Source ✅ ✅ ✅ ✅ Web interface ❌ (console) ✅ ✅ ✅ Performance High Medium Low Medium ACL support ✅ ✅ Limited ❌ Authelia is an excellent choice for those who want maximum security with minimal resource usage, especially in a self-hosted environment.\nPrerequisites # Before installing, make sure you have:\nDocker and Docker Compose A reverse proxy (e.g., Traefik) Configured domains and HTTPS (e.g., via Let\u0026rsquo;s Encrypt) Basic knowledge of YAML and Docker Sample project structure # authelia/ ├── configuration.yml ├── users.yml ├── docker-compose.yml └── secrets services: authelia: image: \u0026#34;authelia/authelia:4.39.20\u0026#34; # don\u0026#39;t use :latest - pin the version explicitly, check the current one at https://github.com/authelia/authelia/releases container_name: \u0026#34;authelia\u0026#34; volumes: - \u0026#34;./secrets:/secrets:ro\u0026#34; - \u0026#34;./config:/config\u0026#34; - \u0026#34;./logs:/var/log/authelia/\u0026#34; networks: proxy: labels: - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.http.routers.authelia.rule=Host(`authelia.domain.ru`)\u0026#34; - \u0026#34;traefik.http.routers.authelia.entrypoints=https\u0026#34; - \u0026#34;traefik.http.routers.authelia.tls=true\u0026#34; - \u0026#34;traefik.http.middlewares.authelia.forwardAuth.address=http://authelia:9091/api/verify?rd=https://authelia.stilicho.ru\u0026#34; - \u0026#34;traefik.http.middlewares.authelia.forwardAuth.trustForwardHeader=true\u0026#34; - \u0026#34;traefik.http.middlewares.authelia.forwardAuth.authResponseHeaders=Remote-User,Remote-Groups,Remote-Name,Remote-Email\u0026#34; - \u0026#34;traefik.http.services.authelia.loadbalancer.server.port=9091\u0026#34; environment: TZ: \u0026#34;Europe/Moscow\u0026#34; AUTHELIA_IDENTITY_VALIDATION_RESET_PASSWORD_JWT_SECRET_FILE: \u0026#34;/secrets/JWT_SECRET\u0026#34; # tr -cd \u0026#39;[:alnum:]\u0026#39; \u0026lt; /dev/urandom | fold -w 64 | head -n 1 \u0026gt; ./secrets/JWT_SECRET AUTHELIA_SESSION_SECRET_FILE: \u0026#34;/secrets/SESSION_SECRET\u0026#34; # tr -cd \u0026#39;[:alnum:]\u0026#39; \u0026lt; /dev/urandom | fold -w 64 | head -n 1 \u0026gt; ./secrets/SESSION_SECRET AUTHELIA_STORAGE_ENCRYPTION_KEY_FILE: \u0026#34;/secrets/STORAGE_ENCRYPTION_KEY\u0026#34; # tr -cd \u0026#39;[:alnum:]\u0026#39; \u0026lt; /dev/urandom | fold -w 64 | head -n 1 \u0026gt; ./secrets/STORAGE_ENCRYPTION_KEY #whoami-secure: # image: \u0026#34;traefik/whoami\u0026#34; # restart: \u0026#34;unless-stopped\u0026#34; # container_name: \u0026#34;whoami-secure\u0026#34; # labels: # - \u0026#34;traefik.enable=true\u0026#34; # - \u0026#34;traefik.http.routers.whoami-secure.rule=Host(`whoami-secure.stilicho.ru`)\u0026#34; # - \u0026#34;traefik.http.routers.whoami-secure.entrypoints=https\u0026#34; # - \u0026#34;traefik.http.routers.whoami-secure.middlewares=authelia@docker\u0026#34; # networks: # proxy: networks: proxy: external: true users: stilicho: ## Username displayname: \u0026#34;stilicho\u0026#34; ## WARNING: This is a default password for testing only! ## IMPORTANT: Change this password before deploying to production! ## Generate a new hash using the instructions at: ## https://www.authelia.com/reference/guides/passwords/#passwords ## Password is \u0026#39;authelia\u0026#39; password: \u0026#34;$argon2id$v=19$m=65536,t=3,p=4$uSPUUUh/a5U7pNso6g2cMA$YJECeQHkv/qXZDB3W9ADkWj7DMSJRWcn/pVHTUvCbtI\u0026#34; email: \u0026#34;authelia@authelia.com\u0026#34; groups: - \u0026#34;admin\u0026#34; - \u0026#34;dev\u0026#34; server: address: tcp://0.0.0.0:9091/ log: level: debug theme: dark # This secret can also be set using the env variables AUTHELIA_JWT_SECRET_FILE #jwt_secret: default_redirection_url: https://authelia.stilicho.ru totp: issuer: authelia.com # duo_api: # hostname: api-123456789.example.com # integration_key: ABCDEF # # This secret can also be set using the env variables AUTHELIA_DUO_API_SECRET_KEY_FILE # secret_key: 1234567890abcdefghifjkl authentication_backend: file: path: /config/users.yml password: algorithm: argon2 # Recommended Parameters # Uses 2 GiB memory, then immediately releases it. # See https://www.authelia.com/reference/guides/passwords/#recommended-parameters-argon2 # See https://www.rfc-editor.org/rfc/rfc9106.html#section-4 for details on tuning the parameters for your hardware. # After saving configuration file, password hash can be generated by running: docker run -v ./configuration.yml:/configuration.yml --rm authelia/authelia:latest authelia crypto hash generate --config /configuration.yml --password \u0026#39;yourpassword\u0026#39; argon2: variant: argon2id iterations: 1 memory: 2097152 parallelism: 4 key_length: 32 salt_length: 16 # Recommended Parameters when constrained by low memory or low powered hardware. Uses 64 KiB memory, then immediately releases it. # argon2: # variant: argon2id # iterations: 3 # memory: 65536 # parallelism: 4 # key_length: 32 # salt_length: 16 access_control: default_policy: deny rules: # Rules applied to everyone - domain: traefik-dashboard.stilicho.ru policy: two_factor #- domain: portainer.stilicho.ru #для portainer есть oidc # policy: two_factor - domain: nginx.stilicho.ru policy: two_factor session: name: authelia_session # This secret can also be set using the env variables AUTHELIA_SESSION_SECRET_FILE #secret: expiration: 14400 # 4 hour inactivity: 14400 # 4 hour domain: stilicho.ru # Should match whatever your root protected domain is # redis: # host: redis # port: 6379 # # This secret can also be set using the env variables AUTHELIA_SESSION_REDIS_PASSWORD_FILE # # password: authelia regulation: max_retries: 3 find_time: 120 ban_time: 300 storage: #encryption_key: /secrets/STORAGE_ENCRYPTION_KEY # Now required local: path: /config/db.sqlite3 #password_policy: # zxcvbn: # enabled: true # min_score: 4 #identity_providers: # oidc: ## The other portions of the mandatory OpenID Connect 1.0 configuration go here. ## See: https://www.authelia.com/c/oidc # clients: # - client_id: \u0026#39;portainer\u0026#39; # client_name: \u0026#39;Portainer\u0026#39; # client_secret: \u0026#39;$pbkdf2-sha512$310000$c8p78n7pUMln0jzvd4aK4Q$JNRBzwAo0ek5qKn50cFzzvE9RXV88h1wJn5KGiHrD0YKtZaR/nCb2CJPOsKaPK0hjf.9yHxzQGZziziccp6Yng\u0026#39; # The digest of \u0026#39;insecure_secret\u0026#39;. # public: false # authorization_policy: \u0026#39;two_factor\u0026#39; # require_pkce: false # pkce_challenge_method: \u0026#39;\u0026#39; # redirect_uris: # - \u0026#39;https://portainer.stilicho.ru\u0026#39; # scopes: # - \u0026#39;openid\u0026#39; # - \u0026#39;profile\u0026#39; # - \u0026#39;groups\u0026#39; # - \u0026#39;email\u0026#39; # response_types: # - \u0026#39;code\u0026#39; # grant_types: # - \u0026#39;authorization_code\u0026#39; # access_token_signed_response_alg: \u0026#39;none\u0026#39; # userinfo_signed_response_alg: \u0026#39;none\u0026#39; # token_endpoint_auth_method: \u0026#39;client_secret_post\u0026#39; #log: # level: info # format: text # file_path: /logs/authelia.log # keep_stdout: false notifier: # smtp: # username: test # # This secret can also be set using the env variables AUTHELIA_NOTIFIER_SMTP_PASSWORD_FILE # password: password # host: mail.example.com # port: 25 # sender: admin@example.com filesystem: filename: /config/notification.txt ","date":"August 6, 2025","externalUrl":null,"permalink":"/en/posts/authelia-docker-install/","section":"Posts","summary":"A step-by-step guide to installing and configuring Authelia in Docker - deployment, 2FA configuration, Traefik integration via forwardAuth, and a breakdown of the main config parameters.","title":"Installing Authelia in Docker | Complete Guide","type":"posts"},{"content":" Introduction # Proxmox VE 9.0 was released on August 5, 2025, gaining a solid foundation built on Debian 13 \u0026ldquo;Trixie\u0026rdquo; and Linux kernel 6.14.8-2. In this article, we\u0026rsquo;ll go through the process of upgrading Proxmox 8 to 9 (Proxmox 8 to 9 upgrade) step by step - from checking compatibility to the final apt dist-upgrade command. This version marks a significant step forward in virtualization, storage, and network infrastructure capabilities.\n1. Updated kernel and base system # Moving to Debian 13 \u0026ldquo;Trixie\u0026rdquo; provides up-to-date packages, improved security, and compatibility with modern hardware: PCIe 5.0, NVMe, new chipsets. Linux kernel 6.14.8-2 is optimized for modern CPUs and network interfaces. Updated versions of QEMU 10.0.2 and LXC 6.0.4 are available, improving VM migration, isolation, and cgroup v2 support. The old cgroup v1 is no longer supported. 2. Storage and snapshots # Support for LVM snapshots on thick-provisioned shared storage (iSCSI, Fibre Channel), which allows creating snapshots with minimal disk overhead and rollback without external tools. ZFS 2.3.3 is enabled with support for RAID-Z expansion - you can add disks to a RAID-Z array without downtime. Ceph storage is now deployed by default on Ceph Squid 19.2.3, with LZ4 compression enabled by default and improved performance for multi-user scenarios. By the way, for a home cluster, Ceph is often overkill - I covered this in more detail in a separate article. 3. Network infrastructure and SDN # SDN Fabrics let you build routable overlay networks between nodes (OpenFabric, OSPF) without external switches - with support for spine-leaf and full-mesh topologies for Proxmox and Ceph clusters. The new proxmox-network-interface-pinning tool allows binding MAC addresses to stable names like nic0, nic1, etc., and automatically adjusts the configuration when NICs are renamed after updates. 4. HA, placement policies, and mobile UI # New HA affinity rules let you define resource (VM/CT) placement across nodes or groups to minimize latency or increase fault tolerance. If your cluster isn\u0026rsquo;t set up yet - see the Proxmox clustering guide. A new mobile interface, built on Rust (the Yew framework), provides convenient management from a smartphone browser: VM management, HA tasks, monitoring, etc. 5. Interface, usability, and vulnerability removal # Dark mode by default - the interface now starts in the dark theme; the light theme is available if explicitly chosen by the user. Improved display of errors, notifications, and logs; fixed issues with the UI, the OIDC window, and ISO template loading - especially in the web interface and backup job notifications. GlusterFS support removed: if you use GlusterFS, you need to migrate to Ceph, ZFS, or NFS before upgrading. 6. Compatibility and migration # Containers on cgroup v1 (CentOS 7, Ubuntu 16.04) are not supported - it\u0026rsquo;s recommended to migrate to a modern OS beforehand. NVIDIA GRID/vGPU users require the GRID 18.3+ driver (version 570.158.02 or newer), compatible with kernel ≥ 6.0. Without it, vGPU support will be broken. 7. Commands from the video # Running the pve8to9 checklist script\npve8to9 --full If no problems are found, proceed to the upgrade.\nUpdating APT repositories\nFirst, let\u0026rsquo;s update the current configuration to the latest package versions on the current release.\napt update apt dist-upgrade pveversion Updating the Debian base repositories to the Trixie version\nUpdate the lists for both the enterprise and regular repository.\nsed -i \u0026#39;s/bookworm/trixie/g\u0026#39; /etc/apt/sources.list sed -i \u0026#39;s/bookworm/trixie/g\u0026#39; /etc/apt/sources.list.d/pve-enterprise.list Adding Proxmox VE 9 package repositories\nFirst, update the enterprise repository data.\ncat \u0026gt; /etc/apt/sources.list.d/pve-enterprise.sources \u0026lt;\u0026lt; EOF Types: deb URIs: https://enterprise.proxmox.com/debian/pve Suites: trixie Components: pve-enterprise Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg EOF Now the same thing, but for normal people.\ncat \u0026gt; /etc/apt/sources.list.d/proxmox.sources \u0026lt;\u0026lt; EOF Types: deb URIs: http://download.proxmox.com/debian/pve Suites: trixie Components: pve-no-subscription Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg EOF Updating the Ceph package repository\nFirst, update the enterprise repository.\ncat \u0026gt; /etc/apt/sources.list.d/ceph.sources \u0026lt;\u0026lt; EOF Types: deb URIs: https://enterprise.proxmox.com/debian/ceph-squid Suites: trixie Components: enterprise Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg EOF Now for us mere mortals.\ncat \u0026gt; /etc/apt/sources.list.d/ceph.sources \u0026lt;\u0026lt; EOF Types: deb URIs: http://download.proxmox.com/debian/ceph-squid Suites: trixie Components: no-subscription Signed-By: /usr/share/keyrings/proxmox-archive-keyring.gpg EOF Updating the repository data\napt update Upgrading the Proxmox kernel\napt dist-upgrade Conclusion # Proxmox VE 9.0 is an important step forward: a new stable base on Debian 13, powerful storage capabilities (ZFS, LVM, Ceph), flexible SDN settings, HA placement control, and a modern mobile UI. However, before upgrading, pay attention to container requirements, network configuration, and vGPU compatibility.\nAlso on this topic: # Proxmox cluster: setup, QDevice, and mixed hardware in nodes Merging local-lvm and local in Proxmox Installing via Cloud-Init in Proxmox ","date":"August 6, 2025","externalUrl":null,"permalink":"/en/posts/upgrade-proxmox8-to-proxmox9/","section":"Posts","summary":"A step-by-step guide to safely migrating from Proxmox 8 to version 9. Covers server preparation, backups, package upgrades, and compatibility checks for virtual machines and containers to minimize downtime.","title":"Upgrading from Proxmox VE 8 to Proxmox VE 9: a step-by-step guide","type":"posts"},{"content":" Что такое ZITADEL? # Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nZITADEL - это система управления идентификацией и доступом (IAM), которую изначально разработала швейцарская компания CAOS AG (Санкт-Галлен). Сейчас проект развивается под брендом ZITADEL Inc., а CAOS AG остаётся швейцарской операционной \u0026ldquo;дочкой\u0026rdquo;. Она предоставляет полный набор функций по управлению пользователями, безопасной аутентификации и авторизации, подходящий как для небольших проектов, так и для крупных корпоративных решений.\nГлавное преимущество ZITADEL - это сочетание открытого исходного кода, современной архитектуры и облачной ориентации, что делает его удобным для DevOps, SaaS-платформ и internal tool-авторизации. Как ZITADEL смотрится на фоне Authelia, Authentik и Keycloak - сравнивал в отдельной статье.\nКлючевые возможности ZITADEL # Поддержка современных протоколов # OIDC (OpenID Connect) OAuth 2.0 SAML 2.0 Это делает Zitadel совместимым с большинством современных веб-приложений и сервисов.\nМногоарендность и управление организациями # Поддержка multi-tenant архитектуры Отдельные пространства для организаций Делегирование прав администраторам Многофакторная аутентификация (MFA) # Email/OTP TOTP (Google Authenticator) SMS WebAuthn (FIDO2, YubiKey и др.) Настраивается централизованно или на уровне организации.\nAPI и CLI # Полноценный REST и gRPC API zitadel CLI Поддержка DevOps-инфраструктуры (CI/CD, GitOps) Ролевое управление доступом # Роли на уровне проектов, приложений и пользователей Кастомные клеймы и scopes в токенах RBAC/ABAC-подход Облачное и локальное развёртывание # Хостинг от разработчиков (SaaS) Self-hosted: Docker, Kubernetes, Podman Поддержка PostgreSQL и CockroachDB Преимущества ZITADEL # Возможность ZITADEL Keycloak Auth0 Authelia / TinyAuth Open Source ✅ ✅ ❌ ✅ OIDC/SAML ✅ ✅ ✅ ❌/частично MFA ✅ ✅ ✅ ❌/частично Multi-tenant ✅ Частично ✅ ❌ UI для self-service ✅ ❌ ✅ ❌ API / CLI ✅ Частично ✅ ❌ Как начать # Пример docker compose файла, который использовался в ролике :\nservices: zitadel: restart: \u0026#34;always\u0026#34; container_name: zitadel networks: - zitadel - proxy image: \u0026#34;ghcr.io/zitadel/zitadel:v4.15.0\u0026#34; # не используйте :latest - зафиксируйте версию явно, актуальную смотрите на https://github.com/zitadel/zitadel/releases command: \u0026#39;start-from-init --masterkey \u0026#34;${MASTERKEY_32}\u0026#34; --tlsMode external\u0026#39; env_file: .env environment: ZITADEL_DATABASE_POSTGRES_HOST: zitadel-db ZITADEL_DATABASE_POSTGRES_PORT: 5432 ZITADEL_DATABASE_POSTGRES_DATABASE: zitadel ZITADEL_DATABASE_POSTGRES_USER_USERNAME: ${DB_USER} ZITADEL_DATABASE_POSTGRES_USER_PASSWORD: ${DB_PASSWORD} ZITADEL_DATABASE_POSTGRES_USER_SSL_MODE: disable ZITADEL_DATABASE_POSTGRES_ADMIN_USERNAME: ${DB_ADMIN_USER} ZITADEL_DATABASE_POSTGRES_ADMIN_PASSWORD: ${DB_ADMIN_PASSWORD} ZITADEL_DATABASE_POSTGRES_ADMIN_SSL_MODE: disable ZITADEL_FIRSTINSTANCE_ORG_HUMAN_USERNAME: ${ZITADEL_LOGIN_USER} ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORD: ${ZITADEL_LOGIN_PASSWORD} ZITADEL_FIRSTINSTANCE_ORG_HUMAN_PASSWORDCHANGEREQUIRED: false ZITADEL_FIRSTINSTANCE_ORG_NAME: HomeLab ZITADEL_PORT: 8080 #For External TLS (Also use h2c) ZITADEL_EXTERNALPORT: 443 ZITADEL_EXTERNALDOMAIN: ${ZITADEL_SUBDOMAIN}.${DOMAIN_NAME} #eg. auth.DOMAIN_NAME ZITADEL_EXTERNALSECURE: true labels: - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.http.routers.zitadel.entrypoints=http\u0026#34; - \u0026#34;traefik.http.routers.zitadel.rule=Host(`${ZITADEL_SUBDOMAIN}.${DOMAIN_NAME}`)\u0026#34; - \u0026#34;traefik.http.middlewares.https-redirect.redirectscheme.scheme=https\u0026#34; - \u0026#34;traefik.http.routers.zitadel.middlewares=https-redirect\u0026#34; - \u0026#34;traefik.http.routers.zitadel-secure.entrypoints=https\u0026#34; - \u0026#34;traefik.http.routers.zitadel-secure.rule=Host(`${ZITADEL_SUBDOMAIN}.${DOMAIN_NAME}`)\u0026#34; - \u0026#34;traefik.http.routers.zitadel-secure.tls=true\u0026#34; - \u0026#34;traefik.http.routers.zitadel-secure.service=zitadel\u0026#34; - \u0026#34;traefik.http.services.zitadel.loadbalancer.server.scheme=h2c\u0026#34; - \u0026#34;traefik.http.services.zitadel.loadbalancer.passHostHeader=true\u0026#34; - \u0026#34;traefik.http.services.zitadel.loadbalancer.server.port=8080\u0026#34; - \u0026#34;traefik.docker.network=proxy\u0026#34; depends_on: zitadel-db: condition: \u0026#34;service_healthy\u0026#34; zitadel-db: restart: \u0026#34;always\u0026#34; container_name: zitadel-db image: postgres:17-alpine env_file: .env environment: POSTGRES_USER: ${DB_ADMIN_USER} POSTGRES_PASSWORD: ${DB_ADMIN_PASSWORD} networks: - zitadel healthcheck: test: [ \u0026#34;CMD-SHELL\u0026#34;, \u0026#34;pg_isready\u0026#34;, \u0026#34;-d\u0026#34;, \u0026#34;zitadel\u0026#34;, \u0026#34;-U\u0026#34;, \u0026#34;${DB_ADMIN_USER}\u0026#34;, ] interval: \u0026#34;10s\u0026#34; timeout: \u0026#34;30s\u0026#34; retries: 5 start_period: \u0026#34;20s\u0026#34; volumes: - ${DB_LOCATION}:/var/lib/postgresql/data networks: zitadel: name: zitadel proxy: external: true name: proxy Пример файла окружения с переменными\nMASTERKEY_32=GENERATE_RANDOM_KEY_LENGTH_32_ChangeMe #Replace Master Key (tr -dc A-Za-z0-9 \u0026lt;/dev/urandom | head -c 32) DB_USER=Enter_DB_User_ChangeMe DB_PASSWORD=Enter_DB_Password_ChangeMe DB_ADMIN_USER=Enter_DB_Root_User_ChangeMe DB_ADMIN_PASSWORD=Enter_DB_Root_Password_ChangeMe ZITADEL_LOGIN_USER=Loginusername@Your_Domain_ChangeMe.com ZITADEL_LOGIN_PASSWORD=Zitadel_Password_ChangeMe ZITADEL_SUBDOMAIN=zitadel DOMAIN_NAME=Your_Domain_ChangeMe.com DB_LOCATION=/path/to/directory/zitadel/zitadel-db ","date":"2 August 2025","externalUrl":null,"permalink":"/posts/zitadel-iam-overview/","section":"Posts","summary":"Пошаговая инструкция по установке и настройке Zitadel для организации двухфакторной аутентификации с обратным прокси. Рассмотрены конфигурация пользователей, интеграция с Docker и рекомендации по повышению безопасности веб-сервисов.","title":"ZITADEL - современное IAM-решение с открытым исходным кодом","type":"posts"},{"content":" Что такое Keycloak # Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nKeycloak - open-source решение для управления идентификацией и доступом (IAM) от Red Hat, с поддержкой SSO, OAuth2, OpenID Connect, SAML 2.0 и ещё доброго десятка стандартов помельче. Это, пожалуй, самый \u0026ldquo;тяжёлый\u0026rdquo; и одновременно самый функциональный игрок из всех IAM-решений, которые я разбирал в этой серии - в enterprise-среде он де-факто стандарт, и если вам когда-нибудь приходилось логиниться в корпоративный портал через страницу с логотипом \u0026ldquo;Keycloak\u0026rdquo; внизу - вот это оно и было.\nВ домашней лаборатории Keycloak оправдан не всегда - он ощутимо тяжелее, чем тот же Authentik или Authelia, и требует Java-стек под капотом. Но если вы хотите пощупать тот самый инструмент, с которым реально работают в проде на работе, или вам нужны специфичные корпоративные фичи вроде реалмов и федерации - это то, что нужно.\nЗачем нужен Keycloak # Централизованно управлять аутентификацией пользователей Keycloak умеет широко:\nединый вход (SSO) сразу во все подключённые приложения; вход через внешних провайдеров - Google, GitHub и другие через OAuth2/OIDC; подключение LDAP и Active Directory, если у вас уже есть корпоративный каталог пользователей; полноценная веб-админка, а не только конфиг-файлы; нативная поддержка OpenID Connect и OAuth 2.0 без костылей. Что понадобится # Docker и Docker Compose; обратный прокси - в этой статье я использую Traefik; домен с настроенным DNS (у меня keycloak.stilicho.ru); SSL-сертификат, проще всего через Let\u0026rsquo;s Encrypt силами того же Traefik. Возможности Keycloak # Возможностей у Keycloak действительно много, и разложу их по смысловым группам, чтобы было понятно, что вообще получаете при установке.\nАутентификация и авторизация. Single Sign-On для всех подключённых приложений, вход через социальные провайдеры (Google, Facebook, GitHub и другие), поддержка OAuth2/OIDC/SAML 2.0 и многофакторная аутентификация через TOTP (Google Authenticator и аналоги).\nУправление пользователями и ролями. Полноценное создание и управление пользователями, группами и ролями, делегированное администрирование - можно разграничить, кто из админов какими пользователями управляет, - плюс импорт и экспорт пользователей через LDAP, CSV или REST API.\nИнтеграция с корпоративной инфраструктурой. Прямая интеграция с LDAP и Active Directory, SCIM-подобные возможности через REST API, полноценный CLI-клиент и Admin REST API для автоматизации.\nMulti-tenancy и реалмы. Пожалуй, главная архитектурная фишка Keycloak - реалмы (realms), изолированные домены аутентификации. У каждого реалма свои настройки, пользователи, клиенты и политики - можно держать один Keycloak на несколько независимых проектов или клиентов, не боясь, что они \u0026ldquo;увидят\u0026rdquo; пользователей друг друга.\nКастомизация. Можно кастомизировать UI экранов входа и регистрации под свой бренд, расширять функциональность через Java SPI и плагины, локализовать интерфейс под нужный язык.\nАудит и безопасность. Аудит логов входа и действий пользователей, гибко настраиваемые политики паролей, ограничения по IP и встроенная защита от brute-force атак.\nDocker Compose файл, который используется в ролике # Ниже - конфигурация, с которой я разворачивал Keycloak в видео. Она состоит из двух сервисов: базы PostgreSQL и самого Keycloak за Traefik.\nservices: postgres: image: postgres:16-alpine container_name: keycloak-db restart: always expose: - 5432 volumes: - /home/path/to/keycloak/database:/var/lib/postgresql/data environment: POSTGRES_DB: ${POSTGRES_DB} POSTGRES_USER: ${POSTGRES_USER} POSTGRES_PASSWORD: ${POSTGRES_PASSWORD} healthcheck: test: [ \u0026#34;CMD\u0026#34;, \u0026#34;pg_isready\u0026#34;, \u0026#34;-q\u0026#34;, \u0026#34;-d\u0026#34;, \u0026#34;${POSTGRES_DB}\u0026#34;, \u0026#34;-U\u0026#34;, \u0026#34;${POSTGRES_USER}\u0026#34;, ] interval: 10s timeout: 5s retries: 3 start_period: 60s networks: - keycloak keycloak: image: quay.io/keycloak/keycloak:26.6.4 # не используйте :latest - зафиксируйте версию явно, актуальную смотрите на https://quay.io/repository/keycloak/keycloak?tab=tags container_name: keycloak command: start environment: KC_HOSTNAME: ${KEYCLOAK_HOSTNAME} KC_BOOTSTRAP_ADMIN_USERNAME: ${KC_BOOTSTRAP_ADMIN_USERNAME} KC_BOOTSTRAP_ADMIN_PASSWORD: ${KC_BOOTSTRAP_ADMIN_PASSWORD} KC_DB: postgres KC_DB_URL: jdbc:postgresql://postgres/${POSTGRES_DB} KC_DB_USERNAME: ${POSTGRES_USER} KC_DB_PASSWORD: ${POSTGRES_PASSWORD} KC_PROXY_HEADERS: \u0026#34;xforwarded\u0026#34; KC_HTTP_ENABLED: true KC_HEALTH_ENABLED: true PROXY_ADDRESS_FORWARDING: \u0026#34;true\u0026#34; healthcheck: test: - \u0026#34;CMD-SHELL\u0026#34; - | exec 3\u0026lt;\u0026gt;/dev/tcp/localhost/9000 \u0026amp;\u0026amp; echo -e \u0026#39;GET /health/ready HTTP/1.1\\r\\nHost: localhost\\r\\nConnection: close\\r\\n\\r\\n\u0026#39; \u0026gt;\u0026amp;3 \u0026amp;\u0026amp; cat \u0026lt;\u0026amp;3 | tee /tmp/healthcheck.log | grep -q \u0026#39;200 OK\u0026#39; interval: 10s timeout: 5s retries: 3 start_period: 90s #ports: # - 8080:8080 #expose: # - 8080 # web ui http # - 9000 # health endpoint restart: always depends_on: postgres: condition: service_healthy networks: - keycloak - proxy labels: - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.http.routers.keycloak.entrypoints=http\u0026#34; - \u0026#34;traefik.http.routers.keycloak.rule=Host(`keycloak.domain.ru`)\u0026#34; - \u0026#34;traefik.http.middlewares.keycloak-https-redirect.redirectscheme.scheme=https\u0026#34; - \u0026#34;traefik.http.routers.keycloak.middlewares=keycloak-https-redirect\u0026#34; - \u0026#34;traefik.http.routers.keycloak-secure.entrypoints=https\u0026#34; - \u0026#34;traefik.http.routers.keycloak-secure.rule=Host(`keycloak.domain.ru`)\u0026#34; - \u0026#34;traefik.http.routers.keycloak-secure.tls=true\u0026#34; - \u0026#34;traefik.http.routers.keycloak-secure.service=keycloak\u0026#34; - \u0026#34;traefik.http.services.keycloak.loadbalancer.server.port=8080\u0026#34; - \u0026#34;traefik.docker.network=proxy\u0026#34; networks: keycloak: internal: true proxy: external: true Значения в файле переменных\n# define FQDN hostname KEYCLOAK_HOSTNAME=keycloak.stilicho.ru # define login credentials KC_BOOTSTRAP_ADMIN_USERNAME=admin KC_BOOTSTRAP_ADMIN_PASSWORD=password # define database credentials POSTGRES_DB=keycloak_db POSTGRES_USER=keycloak_db_user POSTGRES_PASSWORD=keycloak_db_user_password Пару слов про то, что здесь происходит, потому что бездумно копировать чужой compose-файл - плохая идея.\nСеть keycloak намеренно объявлена как internal: true - у базы данных нет и не должно быть прямого выхода наружу, к ней обращается только сам контейнер Keycloak внутри той же docker-сети. Наружу торчит только сеть proxy, через которую Traefik подхватывает контейнер по лейблам.\nKC_PROXY_HEADERS: \u0026quot;xforwarded\u0026quot; и PROXY_ADDRESS_FORWARDING: \u0026quot;true\u0026quot; говорят Keycloak, что он стоит за обратным прокси и должен доверять заголовкам X-Forwarded-* - без этого он будет путаться в том, какой протокол и хост реально использует клиент, и генерировать неправильные redirect-ссылки. KC_HTTP_ENABLED: true разрешает Keycloak слушать по обычному HTTP внутри контейнера - TLS-терминацию в этой схеме на себя берёт Traefik, а не сам Keycloak.\nHealthcheck заслуживает отдельного слова: с определённой версии Keycloak health-эндпоинты переехали на отдельный management-порт 9000, а не висят на основном 8080 вместе с остальным приложением. Именно поэтому в healthcheck используется чистый bash через /dev/tcp вместо curl - в образе Keycloak его попросту нет, а тащить дополнительный пакет ради одной проверки не хочется.\nПервый запуск и создание realm # Разворачиваем всё командой docker compose up -d, ждём, пока пройдёт healthcheck у базы и сам Keycloak поднимется - при первом старте это может занять заметно больше времени, чем последующие рестарты, так как сервис инициализирует внутренние схемы в PostgreSQL.\nПосле этого заходим на https://keycloak.stilicho.ru (у вас, разумеется, будет свой домен) и логинимся под учёткой из KC_BOOTSTRAP_ADMIN_USERNAME/KC_BOOTSTRAP_ADMIN_PASSWORD. Дальше по порядку:\nСоздаём отдельный realm. По умолчанию Keycloak предлагает работать в realm master, но это плохая практика - master предназначен для администрирования самого Keycloak, а не для ваших приложений. В левом верхнем углу выбираем Create realm, даём ему осмысленное имя (например, homelab). Создаём клиента. Внутри свежего realm идём в Clients → Create client, задаём Client ID (обычно совпадает с именем защищаемого сервиса), включаем нужный тип аутентификации (Standard flow для обычного веб-приложения через OIDC) и прописываем Valid redirect URIs - адрес, куда Keycloak будет возвращать пользователя после успешного входа. Заводим пользователей. В Users создаём нужные учётные записи, либо настраиваем интеграцию с внешним LDAP/Active Directory через User federation, если пользователи уже где-то есть и плодить их вручную не хочется. Настраиваем MFA при желании. В Authentication можно обязать конкретные группы пользователей проходить TOTP - это делается через flows, не требует правки конфигов и применяется сразу ко всем клиентам realm. С этого момента любое приложение, поддерживающее OIDC или SAML, можно подключить к этому realm как отдельного клиента - и оно получит единый вход вместе со всеми остальными сервисами, подключёнными тем же способом.\nЗаключение # Keycloak - не самый лёгкий вариант для домашней лаборатории, и если вам нужен просто быстрый forward-auth перед парой сервисов, скорее всего, хватит Authelia или Authentik - я разбирал оба варианта в соседних статьях. Но если вы хотите разобраться с тем самым инструментом, который реально используют в enterprise, потренироваться на реалмах, федерации и делегированном администрировании, или у вас уже есть LDAP/Active Directory, которые нужно подключить как есть - Keycloak оправдывает свой вес с лихвой. Полное сравнение всех четырёх решений (включая ZITADEL) - в отдельной статье.\nСсылки # Документация Keycloak по OIDC и защите приложений ","date":"2 August 2025","externalUrl":null,"permalink":"/posts/keycloak/","section":"Posts","summary":"Пошаговая инструкция по установке и настройке Keycloak для организации SSO и двухфакторной аутентификации с обратным прокси. Рассмотрены конфигурация Docker Compose, первый вход в админку, создание realm и клиента, а также рекомендации по повышению безопасности.","title":"Установка и настройка Keycloak","type":"posts"},{"content":" Comparing Authelia, Authentik, Keycloak, and ZITADEL # If you enjoyed this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\nIntroduction # Today we\u0026rsquo;ll compare four popular solutions for SSO and authorization, in simple terms: authentication and authorization servers - Authelia, Authentik, Keycloak, and Zitadel. If you\u0026rsquo;re building your own home, or maybe even work, infrastructure and don\u0026rsquo;t know what to choose - this article/video is for you.\nWhen you deploy several services, especially ones exposed to the outside world - Nextcloud, Plex, really any service - the question arises: how do you centrally manage login, passwords, and access rights? SSO - Single Sign-On - lets you authenticate once and use that access everywhere. And you can also add two-factor auth, LDAP, OAuth2, split up roles, and configure access policies. For a breakdown of exactly how TOTP, WebAuthn, and passwordless login differ and which to choose, I have a separate article.\nAuthelia vs Authentik vs Keycloak vs ZITADEL - what to choose for authentication and SSO? # If you\u0026rsquo;re building your own infrastructure and looking for a way to implement centralized authentication, two-factor protection, and SSO (Single Sign-On), you\u0026rsquo;ve most likely run into solutions like Authelia, Authentik, Keycloak, and ZITADEL. They all solve the same problem - access management - but they do it differently and are aimed at different scenarios.\nIn this article I\u0026rsquo;ll compare all four tools in detail and suggest which solution best fits your needs: from a simple self-hosted setup to corporate and/or cloud solutions.\nWe\u0026rsquo;ll look at 4 open-source solutions. I\u0026rsquo;ve ordered them alphabetically, but oddly enough, this split also happens to line up with a split in built-in functionality - present in the first pair but absent in the second.\nAuthelia - simple and strict, Authentik - beautiful and flexible, Keycloak - powerful, strict, corporate, Zitadel - cloud-based, with a modern API. Authelia # Authelia is a self-hosted reverse proxy companion designed to protect web applications with two-factor authentication and access control. Authelia works as a proxy companion, adding security and SSO on top of NGINX, Traefik, or HAProxy.\nAuthelia leans more toward being a reverse proxy guard. It\u0026rsquo;s reasonably simple to install, with YAML-based configuration. It works as an intermediate layer between the user and your services. There\u0026rsquo;s no full-fledged UI for managing users - everything goes through the config. Good fit if you have 5-10 services and want to keep everything in config-as-code.\nI covered a step-by-step installation and setup of Authelia in Docker in a separate article.\nKey characteristics of Authelia # Characteristic Description Language Go, React SSO support OIDC as a client only (not a full-fledged IdP) 2FA TOTP, WebAuthn, Duo (including push notifications) UI Limited (has a web login page, but admin configuration is via YAML) LDAP/AD Yes, for authorization and groups Reverse-proxy support Full: Traefik, NGINX, HAProxy Scalability Yes, supports Redis, MariaDB/Postgres Target audience Self-hosted homelab environments and small offices Authentik # Authentik is a modern open-source IdP written in Python (Django) that offers full support for OIDC, SAML, SCIM, a UI, and powerful access policies. It\u0026rsquo;s designed for both home and corporate solutions.\nAuthentik is a visually pleasant, modular, and flexible solution. Simple to install via Docker, excellent documentation. Supports OAuth2, SAML, LDAP, and many other providers. You can build custom policies, UI flows, and custom login templates.\nA detailed review of Authentik\u0026rsquo;s architecture and capabilities is in a separate article, and step-by-step practical guidance on installation, proxy/OIDC providers, and specific scenarios (invitations, password recovery, 2FA, email notifications, Cloudflare Turnstile) is covered in a series of articles in the SSO category.\nKey characteristics of Authentik # Characteristic Description Language Python (Django) SSO support OIDC, SAML (as IdP and SP) 2FA TOTP, WebAuthn, Email OTP, Duo, Push, Social Login UI Modern interface LDAP/AD Yes (as a user source) Workflow / Policies Yes, visual flows, policies, and more Scalability Yes (Docker, Kubernetes, Redis, PostgreSQL support) Target audience Self-hosted, SMB (small and medium business), DevOps Advantages of Authelia and Authentik # Both of these solutions have a built-in web proxy. This means that, integrating seamlessly with a reverse proxy, both solutions can work with applications that have no built-in OIDC mechanism or only support basic HTTP authentication.\nKeycloak # Keycloak is an enterprise open-source solution from Red Hat, designed for centralized authentication and authorization. It\u0026rsquo;s one of the most powerful and flexible IdPs on the market, supporting OIDC, SAML, Kerberos, LDAP, and so on.\nKeycloak is a genuine beast. Support for practically every protocol and scenario. Used in enterprise projects, but requires significant expertise. Configuration can be cumbersome at times, the interface is overloaded, but this solution really does have everything - just like in Greece.\nI covered step-by-step installation, docker-compose configuration, and the first startup with realm creation in a separate article.\nKey characteristics of Keycloak # Characteristic Description Language Java (Quarkus, previously WildFly) SSO support OIDC, SAML, Kerberos, Social Login 2FA TOTP, SMS, Email OTP, WebAuthn UI Powerful, but some may find it overloaded and confusing LDAP/AD Yes (broad support) Extensibility Yes, via SPI, extensions, and the REST API Scalability Excellent, especially for enterprise Target audience Large enterprise, government institutions Zitadel # ZITADEL is a modern, open-source, cloud-native Identity \u0026amp; Access Management solution developed in Switzerland. Its main focus is on security, developers, DevOps, and multitenancy. Available both as a cloud platform and as a self-hosted solution.\nZitadel is the youngest of the bunch, but already fairly mature. It has both a cloud version and an open-source version for Docker. Very clean and minimalist UI, a modern API and SDK, well-suited for a dev-first approach. Well documented, though there\u0026rsquo;s still room for improvement. It\u0026rsquo;s already being actively and widely adopted.\nMore details on ZITADEL\u0026rsquo;s installation and architecture are in a separate article.\nKey characteristics of ZITADEL # Characteristic Description Language Go SSO support OIDC, SAML, SCIM 2FA WebAuthn, TOTP, SMS, Email UI Modern, minimalist, logical, and pleasant LDAP/AD Only with the enterprise subscription (see documentation) Multi-tenant support Yes (one of its main features) Scalability Very high, cloud-first solution Target audience SaaS platforms, DevOps, developers Overall comparison table # Characteristic Authelia Authentik Keycloak ZITADEL Development language Go Python (Django) Java (Quarkus/WildFly) Go Installation method Docker, Kubernetes, Binary Docker, Kubernetes, Binary Docker, Kubernetes, ZIP distribution Docker, Kubernetes, Cloud SSO support (OIDC/SAML) OIDC (as client) OIDC, SAML (IdP and SP) OIDC, SAML, Kerberos OIDC, SAML, SCIM Web UI Limited Yes (modern UI) Yes (rich, but complex) Yes (minimalist UI) 2FA / MFA support TOTP, WebAuthn, Duo TOTP, WebAuthn, Email OTP TOTP, WebAuthn, Email, SMS TOTP, WebAuthn, SMS, Email LDAP / AD integration Authorization via LDAP Yes (as a user source) Yes Enterprise only RBAC / ABAC Via YAML and policy Yes (flow-based) Yes (groups, roles, policies) Yes (RBAC + conditions) Scalability Medium Good Excellent Excellent Cloud-ready No No Partial Yes Open source Yes (Apache 2.0) Yes (MIT) Yes (Apache 2.0) Yes (GNU Affero GPL v3.0) Conclusions # Authelia is not a full-fledged IdP; rather it serves as an intermediate authentication layer between the user and the application.\nAuthentik is actively developed and convenient for self-hosted scenarios with a good UI.\nKeycloak is powerful but heavy. Suited for corporate use.\nZITADEL is cloud-oriented but has a self-hosted option, with an emphasis on developers and security.\n","date":"August 1, 2025","externalUrl":null,"permalink":"/en/posts/sso-comparison/","section":"Posts","summary":"A comparative overview of popular authentication solutions: Authelia, Authentik, Keycloak, and Zitadel. Covers the capabilities, pros and cons of each service, use-case scenarios, and recommendations for choosing the right tool for home or corporate use.","title":"Authelia vs Authentik vs Keycloak vs ZITADEL - which one to choose?","type":"posts"},{"content":" Что такое CrowdSec? # Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nCrowdSec - это современная open-source система безопасности с принципами, схожими с «коллективным фаерволом» (crowdsourced firewall). Она анализирует логи, выявляет подозрительную активность (например, brute-force, сканирование портов, DDoS) и автоматически применяет решения для блокировки или ограничения доступа IP-адресов злоумышленников.\nГлавная особенность CrowdSec - это обмен данными о вредоносных IP-адресах между всеми пользователями системы, с помощью которой создается коллективная база знаний, которая формируется на основе данных всех участников. Таким образом, если один сервер зафиксировал атаку, остальные участники могут заблокировать злоумышленника заранее.\nАрхитектура CrowdSec # CrowdSec построен на модульной архитектуре и глобально разделён на два уровня:\nAgent (движок анализа) - анализирует журналы логов (Nginx, Traefik, SSH, Postfix, системные логи и т.д.). Bouncers (модули блокировки) - применяют решения о блокировке (ban, captcha, throttle) для защиты или разрешения доступа (например, iptables, Nginx middleware, Traefik bouncer). Agent занимается только определением (выявлением) нехороших айпи, а блокировка выполняется bouncers.\nТаким образом, CrowdSec можно легко интегрировать в любую инфраструктуру, не вмешиваясь напрямую в сетевые правила.\nКак работает CrowdSec? # Давайте теперь рассмотрим работу Crowdsec более детально.\n1. Сбор и анализ логов # CrowdSec подключается к логам сервисов (SSH, Nginx, Traefik, Postfix, системные журналы).\nДля анализа используются парсеры, которые приводят логи к единому формату.\n2. Применение сценариев # CrowdSec использует scenarios - наборы правил, описанных в YAML.\nНапример, сценарий ssh-bf определяет, что 5 неудачных попыток входа за 1 минуту считаются атакой.\n3. Создание решений (Decisions) # Если сценарий срабатывает, агент генерирует решение (decision), например:\nban - заблокировать IP. captcha - требовать проверку. throttle - ограничить скорость запросов. 4. Передача решения на Bouncer # Bouncers - это отдельные компоненты, которые реализуют блокировку.\nПримеры:\niptables-bouncer добавляет IP в firewall. traefik-bouncer подключается к Traefik как middleware. nginx-bouncer использует ACL в Nginx. 5. Коллективная защита (Crowd Threat Intelligence) # Агент может отправлять анонимизированные данные о злоумышленниках на центральный сервер CrowdSec.\nВ ответ сервер присылает глобальный список IP-адресов с плохой репутацией, повышая защиту для всех пользователей.\nПреимущества CrowdSec # Коллективная база угроз - защита в реальном времени от IP-адресов, известных в сообществе. Гибкость - поддержка десятков интеграций (Docker, Kubernetes, Traefik, Nginx). Простота - готовые сценарии для популярных сервисов. Совместимость с DevOps - легко встраивается в CI/CD, работает в контейнерах. Почему CrowdSec лучше Fail2Ban # 1. Современная архитектура # Fail2Ban - классическое решение, написанное на Python, работает на уровне анализа логов и блокирует IP через firewall. CrowdSec - современный инструмент, основанный на микросервисной архитектуре и написанный на Go, что делает его более производительным и масштабируемым. 2. Коллективная защита (crowdsourcing) # Fail2Ban блокирует только те IP, которые атакуют конкретный сервер. CrowdSec делится данными о вредоносных IP с глобальной сетью пользователей, формируя динамическую репутационную базу. Ваш сервер защищён не только от атак, которые уже произошли, но и от IP, замеченных в атаках на другие серверы. 3. Поддержка множества источников данных # Fail2Ban в основном анализирует системные логи. CrowdSec поддерживает: логи различных сервисов (Nginx, SSH, Postfix и др.); сетевые потоки (Netfilter, nftables); интеграции с облачными сервисами и API. 4. Гибкая система сценариев (Scenarios) # CrowdSec использует YAML-сценарии, которые описывают сигнатуры атак (brute force, порт-сканирование и т.д.). Добавить новые сценарии можно в 1 клик из официального хаба, без ручного написания фильтров. 5. Производительность # Fail2Ban плохо масштабируется при большом количестве логов, особенно на загруженных серверах. CrowdSec написан на Go и обрабатывает логи асинхронно, что делает его значительно быстрее и менее ресурсоёмким. 6. Модульная структура # CrowdSec разделяет движок анализа (agent) и механизмы блокировки (bouncers). Можно гибко настраивать, куда отправлять блокировки: iptables, nginx, Cloudflare, HAProxy и т.д. 7. Удобные инструменты визуализации # CrowdSec предоставляет консольный CLI с понятной статистикой, есть возможность интеграции с Metabase для графиков и аналитики Также есть понятная графическая консоль для анализа происходящего на сервера (требуется регистрация на сайте разработчика). Fail2Ban ограничивается логами и простыми командами. 8. Простота управления и обновлений # CrowdSec имеет централизованный репозиторий сценариев и автоматические обновления. В Fail2Ban часто нужно самостоятельно обновлять фильтры и regex для новых атак. Вывод:\nCrowdSec - это не просто современный аналог Fail2Ban, а следующее поколение систем защиты, которое сочетает в себе коллективный опыт, высокую производительность и гибкость. Использование CrowdSec - как более современное решение для серверной безопасности, которое сочетает локальный анализ логов с коллективной базой знаний, вместе с обратным прокси (например, Traefik) позволяет создать динамическую и умную защиту для любых веб-приложений.\nВозможности обнаружения атаки # Давайте более подробно поговорим о принципах обнаружения атак. CrowdSec использует трехуровневый подход к обнаружению для защиты систем от известных и новых угроз:\n1. Локальное принятие решений. # Возможности локального принятия решений CrowdSec позволяют обнаруживать атаки и реагировать на них в режиме реального времени по мере их возникновения. Когда подозрительная активность, например, подбор пароля или принудительное HTTP-зондирование, соответствует одному из предопределенных сценариев обнаружения CrowdSec, система запускает локальное решение. Это действие, например, блокировка или ограничение IP-адреса, напрямую устраняет атаки, обнаруженные в системе. Локальные решения гарантируют немедленную блокировку любых новых или ранее неизвестных злоумышленников до того, как они смогут усилить свою активность. Обычно это делается путем анализа файлов журналов. Наконец, метаданные решения, такие как IP-адрес злоумышленника, передаются сообществу CrowdSec через систему анализа киберугроз (CTI) CrowdSec. 2. Удалённое принятие решений. # Функция удалённого принятия решений поддерживается глобальным сообществом CrowdSec и CTI. Когда любой экземпляр CrowdSec по всему миру обнаруживает злоумышленника, эта информация передается в базу данных CrowdSec Cyber Threat Intelligence (CTI) . Такие известные вредоносные IP-адреса затем помечаются для превентивной блокировки во всех других защищённых системах CrowdSec посредством удалённого принятия решений. Этот проактивный уровень позволяет CrowdSec блокировать входящие угрозы на основе коллективных знаний, останавливая известных злоумышленников ещё до того, как они получат доступ к вашим сервисам. Это реализуется с помощью баунсера CrowdSec (например, для обратного прокси-сервера Traefik). 3. AppSec (WAF). # CrowdSec можно настроить в качестве промежуточного ПО (middlewares) в качестве WAF. В этом случае каждый HTTP-запрос ретранслируется на конечную точку AppSec CrowdSec по протоколу TCP/7422, которая анализирует запрос на наличие вредоносных шаблонов. Эти шаблоны могут представлять собой полезную нагрузку для эксплуатации SQL-инъекций, XSS-уязвимостей или командных инъекций. При желании можно использовать известный набор правил OWASP (CRS), который наиболее известен по открытому WAF ModSecurity и используется многими другими поставщиками WAF. Настройка WAF требует времени и часто требует особой настройки для каждого проксируемого приложения. Как указано выше, для принятия решений на локальном уровне CrowdSec поддерживает различные Сценарии. Они обычно поставляются в так называемых Коллекциях.\nСледуя настоящему гайду (простите за высокопарный слог), вы сможете реализовать более 100 сценариев локального принятия решений. Ваши HTTP-сервисы, работающие за Traefik, будут защищены от достаточного большого количества угроз.\nВ этом гайде будем использовать следующие коллекции:\ncrowdsecurity/traefik traefik support: parser and generic http scenarios crowdsecurity/http-cve Detect CVE exploitation in http logs crowdsecurity/base-http-scenarios http common : scanners detection crowdsecurity/sshd support : parser and brute-force detection crowdsecurity/linux core linux support : syslog+geoip+ssh crowdsecurity/appsec-generic-rules A collection of generic attack vectors for additional protection crowdsecurity/appsec-virtual-patching a generic virtual patching collection, suitable for most web servers. crowdsecurity/appsec-crs Appsec: Modsecurity core rule set rules\nЗапуск Crowdsec # Crowdsec может быть установлен и запущен как нативно на базе разных ОС, так и как контейнер в Docker. В этой статье будем говорить о запуске контейнера в Docker, но в будущем рассмотрим возможность запуска Crowdsec нативно вместе с нативной инсталляцией Traefik.\nDocker Compose файл # Сначала давайте составим docker-compose.yml файл, в котором опишем основные параметры Crowdsec\nservices: crowdsec: # Название сервиса image: crowdsecurity/crowdsec:v1.7 # фиксируем актуальную стабильную ветку (1.8 на момент обновления статьи еще в статусе release candidate). latest брать не стоит по тем же причинам, что и для Traefik - обновление образа без предупреждения может принести breaking change container_name: crowdsec # имя контейнера environment: # переменные окружения GID: \u0026#34;${GID-1000}\u0026#34; # права юзера:группы COLLECTIONS: \u0026#34;crowdsecurity/traefik crowdsecurity/http-cve crowdsecurity/base-http-scenarios crowdsecurity/sshd crowdsecurity/linux crowdsecurity/appsec-generic-rules crowdsecurity/appsec-virtual-patching crowdsecurity/appsec-crs\u0026#34; # наименование коллекций, которые будут загружены TZ: Europe/Moscow # часовой пояс. Очень важная настройка, чтобы время событий отображалось правильно volumes: # тома для корректной работы Crowdsec - /home/path/to/crowdsec/db:/var/lib/crowdsec/data/ # путь до базы данных crowdsec. Начиная с версии 1.7 это уже не рекомендация, а обязательное требование - без этого volume контейнер Crowdsec просто не запустится - /home/path/to/crowdsec/config:/etc/crowdsec/ # путь до конфига crowdsec. Этим же volume монтируется и папка acquis.d/ - отдельный volume под нее не нужен - /home/path/to/traefik/logs:/var/log/traefik/:ro # прописываем пути до логов, которые должен парсить crowdsec. Обратите внимание, что права только на чтение - /var/log/auth.log:/var/log/auth.log:ro # - /var/log/syslog:/var/log/syslog:ro # ports: - 127.0.0.1:9876:8080 # смапим порт для локальных firewall баунсеров # expose: # открываем порты под соответствующие задачи - 8080 # http api for bouncers - 6060 # metrics endpoint for prometheus - 7422 # appsec waf endpoint networks: # указываем сеть в которой у нас работает одновременно и обратный прокси traefik, и crowdsec - proxy # security_opt: # задаем ограничения по правам - no-new-privileges:true # restart: unless-stopped # указываем, что в случае падения контейнера, он всегда будет пытаться перезапуститься networks: # указываем что соответствующая сеть у нас внешняя и ее не надо создавать proxy: # external: true # Создаем конфигурацию для парсинга логов # Теперь мы должны подсказать Crowdsec как и где парсить локальные логи нашей Линукс машины и логи обратного прокси Traefik. Также мы указываем порт, по которому у нас будет работать WAF.\nКстати, начиная с версии 1.7 появилась команда cscli setup detect, которая умеет сама сканировать систему и находить установленные сервисы (nginx, ssh, различные логи и т.д.), после чего можно одной командой cscli setup install-acquisition сгенерировать acquisition-файлы под них. Работает это в первую очередь для нативной установки (deb/rpm) и не всегда корректно видит сервисы, спрятанные по нестандартным путям внутри контейнеров, поэтому в данном гайде я по-прежнему показываю ручной способ - он предсказуемее и нагляднее для разбора. Раньше все источники логов приходилось складывать в один файл acquis.yaml через YAML-документы, разделенные ---. Такой способ до сих пор поддерживается, но начиная с версии 1.5 появилась (и с тех пор считается рекомендованной для любой нетривиальной настройки) директория acquis.d/ - в нее можно раскладывать источники по отдельным файлам, по одному на источник. Так удобнее: не надо скроллить один большой файл в поисках нужного источника, и добавление/удаление источника не затрагивает остальные.\nНикакого отдельного volume под acquis.d/ создавать не надо - она уже доступна внутри контейнера, так как мы примонтировали всю папку конфига (/home/path/to/crowdsec/config:/etc/crowdsec/). Просто создаем внутри нее директорию acquis.d и раскладываем по ней такие файлы:\nacquis.d/traefik.yaml:\nfilenames: - /var/log/traefik/*.log labels: type: traefik acquis.d/syslog.yaml:\nfilenames: - /var/log/syslog - /var/log/auth.log labels: type: syslog acquis.d/appsec.yaml:\nlisten_addr: 0.0.0.0:7422 appsec_config: crowdsecurity/appsec-default name: myAppSecComponent source: appsec labels: type: appsec Если позже захотите добавить парсинг логов еще какого-то сервиса - например, Authentik или Nextcloud - просто добавьте отдельный файл acquis.d/authentik.yaml или acquis.d/nextcloud.yaml по тому же принципу, не трогая остальные:\nfilenames: - /var/log/authentik.log labels: type: authentik Создание API Token для нашего Bouncer # Так как надо будет в дальнейшем связать наш обратный прокси Traefik, то нам надо получить соответствующий токен, с помощью которого мы разрешаем доступ Traefik к Bouncer.\nСоздаем токен простой командой в командной строке\ndocker exec crowdsec cscli bouncers add traefik-bouncer Обязательно скопируйте полученный токен в какое-то надежное место, потому что он выводится на экран один раз, и в случае утери токена вам придется все делать с нуля. Это токен мы потом укажем в соответствующем разделе middlewares в динамической конфигурации Traefik.\nНастройка уведомлений # В этой статье я не буду рассказывать как создать свою web панель на сайте разработчика. Документация простая и интуитивно понятная. Регистрируетесь на сайте и следуете инструкциям в зависимости от вашей операционной системы. Ошибиться практически невозможно, кроме как в случае, когда Вы специально хотите ошибиться.\nНо я расскажу как моментально получать уведомления о событиях в Crowdsec, что на мой взгляд намного важнее, чем иметь визуальный контроль над статистикой.\nЯ покажу настройку уведомлений в телеграмме, но вы можете использовать любой сервис для получения уведомлений: e-mail, Gotify, Telegramm и так далее.\nПолный список можно посмотреть тут\nВ принципе вам просто надо настроить два файла:\nСначала вам нужно расскомментировать две строки http_default в файле profiles.yaml, которая находится по пути /path/to/crowdsec/config/profiles.yaml\nВыглядит это все примерно так:\nname: default_ip_remediation #debug: true filters: - Alert.Remediation == true \u0026amp;\u0026amp; Alert.GetScope() == \u0026#34;Ip\u0026#34; decisions: - type: ban duration: 4h #duration_expr: Sprintf(\u0026#39;%dh\u0026#39;, (GetDecisionsCount(Alert.GetValue()) + 1) * 4) notifications: # - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this. # - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this. - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this. # - email_default # Set the required email parameters in /etc/crowdsec/notifications/email.yaml before enabling this. on_success: break --- name: default_range_remediation #debug: true filters: - Alert.Remediation == true \u0026amp;\u0026amp; Alert.GetScope() == \u0026#34;Range\u0026#34; decisions: - type: ban duration: 4h #duration_expr: Sprintf(\u0026#39;%dh\u0026#39;, (GetDecisionsCount(Alert.GetValue()) + 1) * 4) notifications: # - slack_default # Set the webhook in /etc/crowdsec/notifications/slack.yaml before enabling this. # - splunk_default # Set the splunk url and token in /etc/crowdsec/notifications/splunk.yaml before enabling this. - http_default # Set the required http parameters in /etc/crowdsec/notifications/http.yaml before enabling this. # - email_default # Set the required email parameters in /etc/crowdsec/notifications/email.yaml before enabling this. on_success: break Если вы хотите получать уведомления по почте или указанными мессенджерами, то раскомментуруйте соответствующие строки.\nПосле этого необходимо отредактировать файл notifications/http.yaml, который находится по пути /path/to/crowdsec/config/notifications\nВ случае с телеграммом файл выглядит так:\ntype: http # Don\u0026#39;t change name: http_default # Must match the registered plugin in the profile # One of \u0026#34;trace\u0026#34;, \u0026#34;debug\u0026#34;, \u0026#34;info\u0026#34;, \u0026#34;warn\u0026#34;, \u0026#34;error\u0026#34;, \u0026#34;off\u0026#34; log_level: info # group_wait: # Time to wait collecting alerts before relaying a message to this plugin, eg \u0026#34;30s\u0026#34; # group_threshold: # Amount of alerts that triggers a message before \u0026lt;group_wait\u0026gt; has expired, eg \u0026#34;10\u0026#34; # max_retry: # Number of attempts to relay messages to plugins in case of error # timeout: # Time to wait for response from the plugin before considering the attempt a failure, eg \u0026#34;10s\u0026#34; #------------------------- # plugin-specific options # The following template receives a list of models.Alert objects # The output goes in the http request body # Replace XXXXXXXXX with your Telegram chat ID format: | { \u0026#34;chat_id\u0026#34;: \u0026#34;-XXXXXXXXX\u0026#34;, \u0026#34;text\u0026#34;: \u0026#34; {{range . -}} {{$alert := . -}} {{range .Decisions -}} {{.Value}} will get {{.Type}} for next {{.Duration}} for triggering {{.Scenario}}. {{end -}} {{end -}} \u0026#34;, \u0026#34;reply_markup\u0026#34;: { \u0026#34;inline_keyboard\u0026#34;: [ {{ $arrLength := len . -}} {{ range $i, $value := . -}} {{ $V := $value.Source.Value -}} [ { \u0026#34;text\u0026#34;: \u0026#34;See {{ $V }} on shodan.io\u0026#34;, \u0026#34;url\u0026#34;: \u0026#34;https://www.shodan.io/host/{{ $V -}}\u0026#34; }, { \u0026#34;text\u0026#34;: \u0026#34;See {{ $V }} on crowdsec.net\u0026#34;, \u0026#34;url\u0026#34;: \u0026#34;https://app.crowdsec.net/cti/{{ $V -}}\u0026#34; } ]{{if lt $i ( sub $arrLength 1) }},{{end }} {{end -}} ] } url: https://api.telegram.org/botXXX:YYY/sendMessage # Replace XXX:YYY with your API key method: POST headers: Content-Type: \u0026#34;application/json\u0026#34; Все что вам нужно заменить xxxxxx на свои значения соответственно.\nДдя того, чтобы настройки вступили в силу, crowdsec необходимо перезапустить с помощью команды docker compose up -d --force-recreate.\nМожете потестировать работу нотификаций\n# list notifications docker exec crowdsec cscli notifications list # test a notification channel docker exec crowdsec cscli notifications test http_default Давайте уже закончим с предварительной настройкой Crowdsec и перейдем к настройке Traefik\nНастройка обратного прокси Traefik # Основные принципы настройки обратного прокси Traefik можете почитать в статье на сайте. Там же есть ссылка на видео для, скажем так, визуального контроля.\nПоэтому будем считать, что вы знаете что такое обратный прокси Traefik и понимаете принципы его работы.\nПосле настройки докер контейнера с Crowdsec, активирования парсеров логов, получения api токен от нашего bouncer, нам надо связать наш bouncer с нашим обратным прокси и настроить соответствующие middlewares в Traefik.\nДобавить баунсер Crowdsec в Traefik можно несколькими способами. Раньше это делали с помощью forward-auth middleware и установкой отдельного контейнера с баунсером. На просторах интернета вы встретите именно такой, \u0026ldquo;старый\u0026rdquo;, или вернее устаревший, способ. Сейчас все можно сделать с помощью соответствующего плагина для Traefik.\nПрежде всего проверьте настроены ли у вас логи в обратном прокси Traefik.\nНастройка логов в обратном прокси Traefik # Особенно нас интересует access.log, потому что именно он Crowdsec и нужен.\nПриведу выдержку кода из статьи про Traefik, где я описывал параметры статической конфигурации обратного прокси в файле traefik.yaml\nlog: # определяем уровень логирования и путь для логов level: \u0026#34;INFO\u0026#34; filePath: \u0026#34;/var/log/traefik/traefik.log\u0026#34; accessLog: filePath: \u0026#34;/var/log/traefik/access.log\u0026#34; но теперь зададим более широкие параметры для логирования и работы с ними со стороны Traefik.\nТеперь наш раздел в части описания логов будет выглядеть примерно так\nlog: level: \u0026#34;INFO\u0026#34; filePath: \u0026#34;/var/log/traefik/traefik.log\u0026#34; noColor: false # Recommended to be true when using common. When using the \u0026#39;common\u0026#39; format, disables the colorized output maxSize: 100 # In megabytes. Maximum size in megabytes of the log file before it gets rotated. compress: true # gzip compression when rotating. Determines if the rotated log files should be compressed using gzip. # accessLog: addInternals: true #Enables access logs for internal resources (e.g.: ping@internal) filePath: \u0026#34;/var/log/traefik/access.log\u0026#34; bufferingSize: 100 # number of log lines Traefik will keep in memory before writing them to the selected output fields: names: StartUTC: drop # Write logs in Container Local Time instead of UTC. The time at which request processing started. filters: statusCodes: - \u0026#34;204-299\u0026#34; - \u0026#34;400-599\u0026#34; Я хочу, чтобы access.log фильтровал ответы на запросы по соответствующим кодам. Это сильно ускорит работу. Безусловно вы можете задавать те настройки, которые подходят именно вам.\nКстати, можно заставить Traefik писать логи в json формате, - это еще больше ускорит работу Crowdsec по чтению логов.\nОсобенности настройки при использовании Cloudflare # Если ваш обратный прокси-сервер Traefik работает за сетью CDN CloudFlare, вам необходимо указать IP-адреса CloudFlare в Traefik как доверенные IP-адреса. Это необходимо, так как запросы к HTTP-сервису, по сути, передаются через два обратных прокси-сервера - CloudFlare и нашим Traefik. Благодаря этому реальный IP-адрес посетителя будет от нас скрыт, и Traefik будет видеть только запросы, приходящие с серверов CloudFlare.\nТаким образом, логи Traefik будут содержать только IP-адреса CloudFlare, что не поможет CrowdSec проанализировать и заблокировать настоящего субъекта угрозы перед CloudFlare.\nЧтобы исправить это и видеть реальные IP-адреса пользователей, мы определяем все IPv4- и IPv6-адреса сети CDN CloudFlare как доверенные. Таким образом, Traefik будет доверять таким IP-адресам и анализировать специальные заголовки запросов CloudFlare (X-Forwarded-For), содержащие реальный IP-адрес пользователя.\nДля того, чтобы реализовать эту задачу есть несколько методов. Сам я использую специальный плагин для Traefik под названием cloudflarewarp. Есть еще и другие, аналогичные по функционалу плагины, но чтобы не усложнять и так достаточно сложную для восприятия статью, я покажу более понятный метод.\nМы в ручную определим IP-адреса CloudFlare как доверенные в определениях для точек входа Traefik.\nОткройте статический файл конфигурации Traefik traefik.yaml и определите все IPv4- и IPv6-адреса CloudFlare как доверенные IP-адреса для ваших точек входа. Я приведу только часть traefik.yaml файла, которая имеет непосредственное отношение к теме статьи.\nДолжно выглядеть примерно так:\nentryPoints: http: address: :80 forwardedHeaders: trustedIPs: \u0026amp;trustedIps # Start of Cloudlare\u0026#39;s public IP list - 103.21.244.0/22 - 103.22.200.0/22 - 103.31.4.0/22 - 104.16.0.0/13 - 104.24.0.0/14 - 108.162.192.0/18 - 131.0.72.0/22 - 141.101.64.0/18 - 162.158.0.0/15 - 172.64.0.0/13 - 173.245.48.0/20 - 188.114.96.0/20 - 190.93.240.0/20 - 197.234.240.0/22 - 198.41.128.0/17 - 2400:cb00::/32 - 2606:4700::/32 - 2803:f800::/32 - 2405:b500::/32 - 2405:8100::/32 - 2a06:98c0::/29 - 2c0f:f248::/32 # End of Cloudlare\u0026#39;s public IP list http: redirections: entryPoint: to: https scheme: https # HTTPS endpoint, with domain wildcard https: address: :443 forwardedHeaders: # Reuse the list of Cloudflare\u0026#39;s public IPs from above trustedIPs: *trustedIps http: tls: ..... ..... Внимание! С помощью параметра \u0026amp;trustedIps мы можем сохранить определение - что такое trustedIPs - как переменную. Это позволит нам повторно использовать это определение в разделе trustedIps в точке входе https без необходимости заново прописывать все IP-адреса CloudFlare еще раз. После этого перезапускаем Traefik и смотрим access.log Traefik. В журнале вы теперь не должны видеть обезличенные IP-адреса CloudFlare.\nПлагин CrowdSec Bouncer # Сначала нам нужно установить соответствующий плагин, конфигруацию которого можете посмотреть здесь\nДанный плагин обладает обширными возможностями по настройке, но я буду рассказывать только об одной из функций - блокировка \u0026ldquo;нехороших\u0026rdquo; айпи.\nОткрываем файл статической конфигурации Traefik traefik.yamlи добавляем в него определение плагина:\n# crowdsec bouncer experimental: plugins: bouncer: # это название плагина, которое мы ему присвоили, чтобы в будущем связать это определение со значениями в динамической конфигурации Traefik moduleName: github.com/maxlerebourg/crowdsec-bouncer-traefik-plugin version: v1.7.1 # актуальная версия плагина на момент обновления статьи, сверьте с релизами на github перед установкой Можете перезагрузить Traefik и посмотреть в traefik.log загрузился ли плагин.\nMiddleware CrowdSec Bouncer в Traefik # После скачивания и включения плагина CrowdSec bouncer в файле статической конфигурации Traefik нам необходимо связать его с конкретным middleware для того, чтобы все заработало. Потому что в данный момент, несмотря на то, что плагин скачан и включен, он не функционирует. Сравним это как с работой автомобиля на холостом ходу. Вроде бы двигатель и работает, но мы никуда не едем, только бензин жжем, ну или электроэнергию, если у вас \u0026ldquo;электричка\u0026rdquo;.\nОпределение соответствующему middleware будет задано в файле динамической конфигурации config.yaml (у вас он может называться по другому). В нем мы укажем все необходимые настройки для нашей реализации CrowdSec. Для этого отредактируем файл динамической конфигурации Traefik и определим следующее middleware:\nhttp: middlewares: crowdsec: plugin: bouncer: enabled: true logLevel: INFO updateIntervalSeconds: 15 updateMaxFailure: 0 defaultDecisionSeconds: 15 httpTimeoutSeconds: 10 crowdsecMode: stream crowdsecAppsecEnabled: true crowdsecAppsecHost: crowdsec:7422 crowdsecAppsecFailureBlock: true crowdsecAppsecUnreachableBlock: true crowdsecLapiKey: yourlapikey # Replace CrowdSec API key (docker exec crowdsec cscli bouncers add crowdsecBouncer) crowdsecLapiHost: crowdsec:8080 crowdsecLapiScheme: http forwardedHeadersTrustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 clientTrustedIPs: - 10.0.0.0/8 - 172.16.0.0/12 - 192.168.0.0/16 Как вы видите, мы с вами задали определенные параметры в middleware. При этом, как я указывал выше, вариантов настроек намного, намного больше. Подробнее об этом можно узнать в официальной документации.\nОбязательно внесите в соответствующее поле значения вашего api key, который мы создали ранее.\nТакже обратите внимание, что мы задали значение forwardedHeadersTrustedIPs и clientTrustedIPs. Тем самым мы определяем подсети IPv4 частного класса как доверенные IP-адреса. Это необходимо, поскольку мы хотим доверять HTTP-заголовкам нашего обратного прокси-сервера Traefik, таким как X-Forwarded-For и X-Real-IP. Эти заголовки обычно определяют реальные IP-адреса посетителей нашего сайта, ну и злоумышленников конечно, которые CrowdSec использует для принятия решений и блокировки.\nВы можете сделать более тонкую настройку и добавить точный IP-адрес Traefik в диапазоне /32. Однако добавление всех диапазонов частных классов в белый список - более удобный подход. Особенно это касается динамических IP-адресов подсетей Docker, которые могут меняться при перезагрузке контейнера.\nС помощью переменной clientTrustedIPs мы указываем доверенные IP-адреса или диапазоны IP-адресов, которые мы считаем заслуживающими доверия. Эти IP-адреса или диапазоны сетей не будут заблокированы или запрещены CrowdSec. По сути, это вариант с использованием белого списка.\nВ моём случае я доверяю локальной сети LAN, что отражается в добавлении всех диапазонов частных классов в белый список. Вы можете ограничить их диапазоном вашей текущей подсети LAN (CIDR) в случае необходимости.\nЗащита веб-сервисов Traefik # Несмотря на тот факт, что мы с вами загрузили плагин, связали его с соответствующим middleware, в котором мы определели соответствующие настройки, наши сервисы пока не защищены. То есть наш обратный прокси знает, что есть кaкой-то плагин, и он даже может защищать сервисы, но вот какие сервисы надо защитить Ttraefik пока не знает. Давайте этим и займемся/\nЗащита индивидуальных сервисов с помощью labels # По общему правилу можно активировать недавно добавленное middleware CrowdSec индивидуально для каждого контейнера через метки (labels) Traefik. Я покажу это на примере тестового контейнера, который был создан разработчиками Traefik как раз для тестовых задач.\nwhoami: image: traefik/whoami container_name: whoami-crowdsec-test command: - --name=whoami networks: - proxy labels: - traefik.enable=true - traefik.docker.network=proxy - traefik.http.routers.whoami.rule=Host(`whoami.мойдомен.ru`) - traefik.http.routers.whoami.service=whoami - traefik.http.services.whoami.loadbalancer.server.port=80 ** - traefik.http.routers.whoami.middlewares=crowdsec@file** networks: proxy: external: true Как вы можете увидеть, в последней метке мы определяем тут самую, нужную нам middleware, которая говорит Traefik, что он должен применить соответствующую middleware и говорим, что данные о middleware надо смотреть в файле динамической конфигурации.\nЗащита на уровне entrypoints # Но более правильно, как мне кажется, защитить все сервисы, которые у нас работают за обратным прокси Traefik.\nПреимущество данного решения в том, что мы на глобальном уровне все защищаем и спим спокойно, как будто налоги заплатили. Голова не болит какой сервис под защитой, а какой нет. Они все под защитой. Речь конечно о сервисах, которые спрятаны за Traefik.\nСоответственно я отредктирую файл статической конфигурации Traefik traefik.yaml, который у нас примет следующий вид.\n# Traefik entrypoints (network ports) configuration entryPoints: http: address: :80 forwardedHeaders: trustedIPs: \u0026amp;trustedIps # Start of Cloudlare\u0026#39;s public IP list - 103.21.244.0/22 - 103.22.200.0/22 - 103.31.4.0/22 - 104.16.0.0/13 - 104.24.0.0/14 - 108.162.192.0/18 - 131.0.72.0/22 - 141.101.64.0/18 - 162.158.0.0/15 - 172.64.0.0/13 - 173.245.48.0/20 - 188.114.96.0/20 - 190.93.240.0/20 - 197.234.240.0/22 - 198.41.128.0/17 - 2400:cb00::/32 - 2606:4700::/32 - 2803:f800::/32 - 2405:b500::/32 - 2405:8100::/32 - 2a06:98c0::/29 - 2c0f:f248::/32 # End of Cloudlare public IP list http: redirections: entryPoint: to: https scheme: https # HTTPS endpoint, with domain wildcard https: address: :443 forwardedHeaders: # Reuse the list of Cloudflare\u0026#39;s public IPs from above trustedIPs: *trustedIps http: middlewares: - crowdsec@file # reference to a dynamic middleware for enabling crowdsec bouncer Как вы видите я применил соответствующее middleware на порту 443, но можно применить соответствующее middleware и по порту 80.\nПосле это перезагрузите контейнер Traefik\nПроверка работоспособности Crowdsec. # Мы с вами долго все настраивали, но давайте теперь проверим работоспособность всей это конструкции. А то вдруг все было \u0026ldquo;зазря\u0026rdquo;.\nНиже я приведу список команд, которые нам с вами точно понадобятся.\nСначала проверим, видит ли наш Crowdsec наш Traefik\nЭта команда показывает метрики нашего Crowdsec, а также мы узнаем, видит ли Crowdsec логи Traefik и парсит ли он их\ndocker exec crowdsec cscli metrics # For Metrics and log read checking После ввода, указанной выше команды, вы увидите, или должны увидеть большое количество таблиц, которые показывают нам о том, какие коллекции были загружены, но самая верхняя таблица покажет нам видит ли наш Crowdsec access.log обратного прокси. Если не видит, то перезагрузите сначала Crowdsec, а потом Traefik.\nНачиная с версии 1.7 появилась ещё и более детальная статистика по парсингу - сколько строк прочитано и разобрано по каждому источнику логов отдельно (parsed, unparsed, whitelisted). Посмотреть её можно командой:\ndocker exec crowdsec cscli machines inspect \u0026lt;имя машины\u0026gt; # детальная статистика парсинга по каждому datasource, помогает поймать неправильно настроенный acquis.yaml Имя своей машины можно узнать командой docker exec crowdsec cscli machines list.\nДанная команда обновляет все списки наших коллекций.\ndocker exec crowdsec cscli hub update \u0026amp;\u0026amp; docker exec crowdsec cscli hub upgrade # Security List update command Вместо того, что бы руками каждый раз обновлять списки, имеет смысл настроить cronjob по команде\ncrontab -e если вы пользуетесь дебиано/убунту подобным дистрибутивом.\n* * * * * docker exec crowdsec cscli hub update \u0026amp;\u0026amp; docker exec crowdsec cscli hub upgrade Укажите ту периодичность обновления, которую вы считаете нужным. Можно свериться с любым cronjob калькулятором\nНу и самое важное. Надо проверить, а может ли наш Crщwdsec банить нехорошие ip адреса.\nТем, кто работает в сфере it безопасности не составит труда симулировать атаку, но мы люди от сохи, простые, поэтому сделаем следующее.\nСначала надо закомментировать в middleware доверенные частные подсети, потому что мы работаем из локальной сети и для теста нам надо, чтобы Corwdsec проверял по умолчанию все ip адреса без исключения.\nПотом мы с вами в ручном режиме забаним ip нашего рабочего компьютера следующей командой\ndocker exec crowdsec cscli decisions add --ip 192.168.x.x # add ip to crowdsec decisions block list Теперь мы можем посмотреть список забаненных адресов с помощью команды\ndocker exec crowdsec cscli decisions list # List crowdsec ip decisions В этом списке вы должны увидеть свой ip адрес. Теперь попробуйте зайти на сайт дэшборда вашего обратного прокси Traefik, но только в режиме инкогнито вашего браузера.\nЕсли все нормально, то в доступе вам будет отказано. По умолчанию бан действует 4 часа. Но конечно не надо ждать эти 4 часа, а разбаним себя в ручном режиме.\ndocker exec crowdsec cscli decisions delete --ip 192.168.x.x # delete ip from crowdsec decisions block list Так как у нас все в порядке, а я надеюсь, что все в порядке, то теперь можете разкомментировать наши частные подсети в middlewares\nЕсли вы просто хотите посмотреть весь список предупреждений, который выдает ваш Crowdsec, то сделать это можно с помощью команды\ndocker exec crowdsec cscli alerts list Ну, а на этом все, дорогие друзья.\nЕсли вам понравилась данная статья, то можете поддержать меня boosty.\n","date":"27 July 2025","externalUrl":null,"permalink":"/posts/crowdsec-in-docker/","section":"Posts","summary":"Подробная инструкция по установке и настройке CrowdSec в Docker - контейнере. Рассмотрены шаги от развертывания до интеграции с защитой сервера и мониторингом активности, чтобы быстро обезопасить ваш хостинг и сервисы.","title":"CrowdSec в Docker: установка и защита сервера от атак","type":"posts"},{"content":" Traefik Reverse Proxy in Docker: A Complete Configuration Guide # If you enjoyed this article, you can support the author by becoming a sponsor on Boosty.\nA reverse proxy is a server that accepts requests from clients and forwards them to internal services. It acts as an intermediary between the user and your web application, hiding the real architecture and providing convenient features: load balancing, caching, SSL termination, domain-based routing, and much more.\nIn this article we\u0026rsquo;ll take a detailed look at what a reverse proxy is, why you need one, and walk through setting up Traefik in Docker.\nWhat is a reverse proxy and why do you need one? # A reverse proxy is an important component of modern infrastructure. Its main advantages:\nA single entry point for all services - you can use one IP and different domains or subdomains for many applications. There\u0026rsquo;s no need to open different ports on the router for different applications. We only need port 80 and 443. Security - hiding internal services behind a proxy, protection from direct access. SSL support - automatic generation and renewal of HTTPS certificates with Let\u0026rsquo;s Encrypt. Our connection is encrypted, and the browser doesn\u0026rsquo;t complain about an insecure connection. Load balancing - distributing requests across multiple containers or servers. Not as critical for a home setup, but in a production environment it\u0026rsquo;s simply a necessity. Flexible routing - you can configure rules, redirects, and rewrites for different applications. Features of the Traefik reverse proxy # Traefik is a modern cloud-native reverse proxy and load balancer. Its distinguishing features:\nDynamic configuration - Traefik dynamically discovers Docker containers and automatically configures routes. No need to restart to apply changes to the dynamic configuration. Let\u0026rsquo;s Encrypt integration with a built-in ACME client - automatic issuance and renewal of SSL certificates. No need to track the expiration date of your SSL certificate - Traefik renews it itself when needed. Support for multiple providers - Docker, Kubernetes, Consul, and so on. A handy monitoring panel - a web interface for viewing routes and status. Yes, it\u0026rsquo;s not a management panel, just a monitoring one, but a very informative one. Flexible routing and middleware - you can add authentication, redirects, rate limiting, and so on. This is really the whole point. Traefik is a great fit for DevOps and production environments that use Docker Compose or Kubernetes. It\u0026rsquo;s also worth noting that Traefik has more functionality than Nginx Proxy Manager, which is popular in the homelab community, and if you pay attention, you\u0026rsquo;ll notice that many top YouTube bloggers use it precisely because of that functionality. It\u0026rsquo;s also used in popular applications like Pangolin or Netbird.\nWhat Routers, Middlewares, and Services are in the Traefik reverse proxy # Traefik\u0026rsquo;s configuration uses three main components: routers, services, and middlewares.\nRouters\nRouters are like frontends: they manage incoming requests. In the \u0026ldquo;Routers\u0026rdquo; section you define the entrypoint, who resolves the certificates, and the rules for the request.\nServices\nServices are like backends: they define where to send requests. Here you specify the port that Traefik will use for proxying, and any additional load balancers.\nMiddlewares\nOne of the most complex, but also most interesting features of Traefik. Middlewares modify the request and effectively act as \u0026ldquo;middleware\u0026rdquo; between routers and services. You can easily add elements like headers, authentication, path prefixes, or combine them into groups (chains) for reuse.\nWith these three concepts we: identify incoming requests; determine where the request is routed; and choose how we want to modify the request as it\u0026rsquo;s routed.\nConfiguring Traefik # There are many ways to configure Traefik, and it can be quite confusing for beginners. Who am I kidding - for beginners it will simply be very hard. Even with some experience, I sometimes can\u0026rsquo;t immediately figure out how to configure Traefik, or how to issue a certificate for some service whose setup might require special headers.\nSo let\u0026rsquo;s spend some time on a few important configuration details, namely static and dynamic configuration.\nDynamic configuration # Traefik is a dynamic reverse proxy, meaning it can automatically (on the fly) add and remove routes as containers start or stop, and apply other changes as well.\nDynamic configuration can be specified in two places:\nWith the Docker provider, using labels in Docker Compose for each service. Note that although Traefik doesn\u0026rsquo;t require a restart, a service with labels does need to be recreated (I cover what these labels mean in the video, linked at the start of this article).\nWith the File Provider - YAML files in the \u0026ldquo;rules\u0026rdquo; folder (more on this below). This doesn\u0026rsquo;t require restarting or reinstalling any services and is genuinely dynamic. This is the method I demonstrate in this article.\nStatic configuration # Although dynamic configuration is one of Traefik\u0026rsquo;s main advantages, it\u0026rsquo;s important to understand that Traefik also uses static configuration, which is defined differently and must be stored separately.\nTo apply changes to the static configuration, Traefik must be restarted. There are three different ways to define Traefik\u0026rsquo;s static configuration. Only one of them can be used at a time.\nA configuration file - can be in different formats, but I use YAML (traefik.yaml).\nCommand-line arguments (CLI) - these arguments are passed when the Docker container starts. I don\u0026rsquo;t use this option, both because of the sheer number of commands and because it\u0026rsquo;s harder to grasp the volume of information. But that\u0026rsquo;s a matter of personal preference.\nA list of all the variables can be found at this link\nSetting up SSL certificate issuance # What we need for a fully working reverse proxy # We need a qualified domain name. When buying a domain name, I recommend paying attention not to the purchase price (that\u0026rsquo;s usually roughly the same everywhere), but to the renewal price. Because the ratio between the purchase price and the renewal price can be an unpleasant surprise. I personally use the services of smartape. The renewal cost for a domain in the .ru zone with them is 200 rubles. You can follow the referral link and check the current price. Not an ad.\nNext, we need to point our domain name to external DNS servers. I personally use Cloudflare, but due to RKN blocking, access to their DNS might not work. And although I keep using Cloudflare, given the current restrictions I can\u0026rsquo;t really recommend them. That said, in this article I\u0026rsquo;ll demonstrate the setup specifically with Cloudflare. A list of DNS providers can be found in the Lego documentation - this is the exact ACME client used inside Traefik under the hood, and Traefik itself now simply pulls the current list from there. There are domestic services listed there too - you just need to check the provider code and environment variables when configuring.\nIt\u0026rsquo;s preferable to have a public IP address, which you can get from your internet provider, but it\u0026rsquo;s not required if you\u0026rsquo;re using DNS challenge.\nSet up split DNS so that requests to subdomain names don\u0026rsquo;t leave the local network. You can find more detail in my video dedicated specifically to that topic.\nDNS settings with Cloudflare # I\u0026rsquo;m assuming you already have a registered domain name and it\u0026rsquo;s already pointed to the DNS servers of the corresponding provider. I\u0026rsquo;ll demonstrate everything using Cloudflare as an example. In this guide I use the domain name stilicho.ru The screenshots aren\u0026rsquo;t mine - they\u0026rsquo;re taken from the internet.\nGo to your profile\nGo to the menu for creating a token\nStart creating a custom token\nSet the specific token settings\nCreate the token\nCopy your token value and save it somewhere safe, because you won\u0026rsquo;t be able to view the token value again in the Cloudflare profile. We\u0026rsquo;ll use the resulting token when configuring our proxy as a service, and it lets us manage our certificates through Cloudflare. If you lose the token, the only way out is to recreate it from scratch.\nYou can view all the tokens you\u0026rsquo;ve created via Cloudflare\nSetting up Traefik in Docker # Step 1. Create docker-compose.yml # services: traefik: image: traefik:v3.7 # Pin the minor version (the current stable branch as of this article\u0026#39;s update - v3.7). It\u0026#39;s best not to use the latest tag - updating the image without warning could bring in a breaking change container_name: traefik # Container name restart: unless-stopped # Tell Docker to always try to restart the container in case of an unexpected stop security_opt: - no-new-privileges:true # Don\u0026#39;t allow the container to gain additional privileges without our knowledge networks: proxy: # the container will run on a specific Docker network called \u0026#39;proxy\u0026#39; ports: - 80:80 # define the HTTP port - 443:443 # define the HTTPS port environment: - CF_API_EMAIL=mail@gmail.com # Specify your email address, which serves as your Cloudflare account for obtaining an API token - CF_DNS_API_TOKEN=apitoken # specify the value of the obtained token volumes: - /etc/localtime:/etc/localtime:ro # sync the container\u0026#39;s time with the host\u0026#39;s time - /var/run/docker.sock:/var/run/docker.sock:ro # Allow Traefik to interact directly with Docker - /home/user/docker/traefik/traefik.yaml:/traefik.yaml:ro # specify where the Traefik static config file is located - /home/user/docker/traefik/acme.json:/acme.json # specify where all our SSL certificate data will be stored - /home/user/docker/traefik/config.yaml:/config.yaml:ro # Specify where the dynamic config file is stored - /home/user/docker/traefik/logs:/var/log/traefik # specify the path to the directory where Traefik logs and the access log will be stored labels: - \u0026#34;traefik.enable=true\u0026#34; # Enable Traefik for this service - \u0026#34;traefik.http.routers.traefik.entrypoints=http\u0026#34; # Define the HTTP entrypoint - \u0026#34;traefik.http.routers.traefik.rule=Host(`traefik-dashboard.user.ru`)\u0026#34; # Define the host rule for routing - \u0026#34;traefik.http.middlewares.traefik-auth.basicauth.users=user:password\u0026#34; # Attach basic authentication to protect our Traefik, specifying the login and password in hashed form - \u0026#34;traefik.http.middlewares.traefik-https-redirect.redirectscheme.scheme=https\u0026#34; # Specify that HTTP traffic should be redirected to HTTPS traffic - \u0026#34;traefik.http.middlewares.sslheader.headers.customrequestheaders.X-Forwarded-Proto=https\u0026#34; # Set the header forwarding for SSL - \u0026#34;traefik.http.routers.traefik.middlewares=traefik-https-redirect\u0026#34; # Apply the HTTPS redirect middleware to redirect HTTPS traffic - \u0026#34;traefik.http.routers.traefik-secure.entrypoints=https\u0026#34; # The secure entrypoint for HTTPS - \u0026#34;traefik.http.routers.traefik-secure.rule=Host(`traefik-dashboard.user.ru`)\u0026#34; # Host rule for HTTPS routing - \u0026#34;traefik.http.routers.traefik-secure.middlewares=traefik-auth\u0026#34; # Apply the authentication middleware - \u0026#34;traefik.http.routers.traefik-secure.tls=true\u0026#34; # Enable TLS for a secure connection - \u0026#34;traefik.http.routers.traefik-secure.tls.certresolver=cloudflare\u0026#34; # Use Cloudflare to issue certificates - \u0026#34;traefik.http.routers.traefik-secure.tls.domains[0].main=user.ru\u0026#34; # The second-level domain name the SSL certificate is issued for - \u0026#34;traefik.http.routers.traefik-secure.tls.domains[0].sans=*.user.ru\u0026#34; # Issue a wildcard SSL certificate for all subdomain names within the domain defined by the rule above - \u0026#34;traefik.http.routers.traefik-secure.service=api@internal\u0026#34; # Define the internal service for the Traefik API networks: proxy: name: proxy # Define the external network to join external: true # Specify that the network is external Step 2. Create traefik.yaml # api: dashboard: true #enable the dashboard debug: true # enable debug level entryPoints: # define entry points http: # name of the entry point address: \u0026#34;:80\u0026#34; # the port associated with the name http http: # the following five lines tell us that at the global level we force all traffic arriving on port 80 to go to port 443 redirections: entryPoint: to: https scheme: https https: # name of the entry point address: \u0026#34;:443\u0026#34; # the port associated with the name https http: # block with HTTP-specific settings for the entry point encodedCharacters: # Allowed encoded characters (important for Trilium) allowEncodedSlash: true # Allow %2F allowEncodedPercent: true # Allow %25 allowEncodedHash: true # Allow %23 serversTransport: # the following two lines allow us to use self-signed SSL certificates for services that use them, such as Proxmox insecureSkipVerify: true providers: # define the configuration providers - Docker and the dynamic configuration file docker: endpoint: \u0026#34;unix:///var/run/docker.sock\u0026#34; exposedByDefault: false file: filename: /config.yaml certificatesResolvers: # define who acts as the certificate resolver cloudflare: # who exactly, specify that acme should be used; specify the email used in Cloudflare acme: email: mail@gmail.com #add your email storage: acme.json # define the file where all the SSL certificate information will be stored dnsChallenge: # use the DNS challenge method for obtaining SSL certificates provider: cloudflare # provider: vultr resolvers: - \u0026#34;1.1.1.1:53\u0026#34; - \u0026#34;1.0.0.1:53\u0026#34; log: # define the logging level and log path level: \u0026#34;INFO\u0026#34; filePath: \u0026#34;/var/log/traefik/traefik.log\u0026#34; accessLog: filePath: \u0026#34;/var/log/traefik/access.log\u0026#34; Step 3. Create the dynamic configuration file # In the dynamic configuration, we specify which routes (routers) our services (services) live on. We specify which subdomain name a certificate should be issued for for a given service, and which middlewares need to be applied. In the file below, we issue an SSL certificate for our Proxmox node, so that the node is accessible via a nice-looking subdomain name.\nhttp: #region routers routers: proxmox: entryPoints: - \u0026#34;https\u0026#34; rule: \u0026#34;Host(`proxmox.DOMAIN_NAME.ru`)\u0026#34; # replace with your domain name middlewares: - default-headers - https-redirect tls: {} service: proxmox # #region services # services: proxmox: loadBalancer: servers: - url: \u0026#34;https://ip:8006\u0026#34; # specify your IP passHostHeader: true # # region middlewares # middlewares: # define which middlewares we want to use going forward. Full list on the traefik.io website # https-redirect: # redirects the request if the request scheme differs from the configured scheme redirectScheme: scheme: https permanent: true # default-headers: # manages request and response headers headers: frameDeny: true browserXssFilter: true contentTypeNosniff: true forceSTSHeader: true stsIncludeSubdomains: true stsPreload: true stsSeconds: 15552000 customFrameOptionsValue: SAMEORIGIN customRequestHeaders: X-Forwarded-Proto: https default-whitelist: # local firewall that works on the principle of allowing requests only from specific IPs ipAllowList: sourceRange: - \u0026#34;10.0.0.0/8\u0026#34; - \u0026#34;192.168.0.0/16\u0026#34; - \u0026#34;172.16.0.0/12\u0026#34; Step 4. Create acme.json # touch /etc/traefik/acme.json - create the file that will store our certificate data\nchmod 600 /etc/traefik/acme.json - set the required permissions on the acme.json file. Otherwise Traefik simply won\u0026rsquo;t start. I think having this kind of safeguard against foolishness is a big plus.\nStep 5. Starting the Traefik container # docker network create proxy - create a Docker network named proxy\nsudo apt install apache2-utils - install the Apache2 utilities package\necho $(htpasswd -nB user) | sed -e s/\\\\$/\\\\$\\\\$/g - create a hashed password for our dashboard\ndocker compose up -d - start the container\nIf everything\u0026rsquo;s fine on your end - you can check this in the traefik.log log - then when we navigate to the link for the Traefik dashboard at traefik-dashboard.user.ru, we should: first, get that access, and second, be able to see our certificate details in the browser. You can also view the certificate data in the acme.json file.\nIf everything\u0026rsquo;s fine, then you now have a fully prepared reverse proxy that\u0026rsquo;s standing by, ready to start issuing SSL certificates for everything. But of course, along with this article, it\u0026rsquo;s better to also watch the video, since it provides a visual walkthrough of how to issue certificates using labels in Docker.\n","date":"July 25, 2025","externalUrl":null,"permalink":"/en/posts/traefik-in-docker/","section":"Posts","summary":"A step-by-step guide to installing and configuring Traefik in Docker to set up a reverse proxy and manage web traffic. Covers container configuration, routing, SSL integration, and recommendations for managing web services.","title":"Traefik in Docker: setting up a reverse proxy from scratch","type":"posts"},{"content":"","date":"July 20, 2025","externalUrl":null,"permalink":"/en/tags/cloudinit/","section":"Tags","summary":"","title":"Cloudinit","type":"tags"},{"content":" If you liked this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\nWhat is Cloud-Init and why do you need it? # Cloud-Init is a tool for automating the initial setup of virtual machines. It allows you to automatically configure:\nthe hostname, network interfaces, users and passwords, SSH keys, scripts that run on first boot. Combined with Proxmox VE, Cloud-Init helps quickly deploy identical VMs with minimal manual effort. It\u0026rsquo;s especially useful in homelab environments, where deployment speed and reproducibility matter.\nTasks solved with Cloud-Init images # Automation. Removes the need to manually configure each new VM. Standardization. All machines are deployed from a single standard template. Security. You can set SSH keys right away and disable the root password. Scalability. Ideal for deploying dozens of VMs in a cluster. Of course, that\u0026rsquo;s unlikely to be needed at home, but if you need it at work, you can practice on test subjects first. CI/CD compatibility. Images can be used for automated testing and infrastructure delivery. But, as I said above, for home use it\u0026rsquo;s more of a testing ground. In Proxmox VE 8, Cloud-Init is integrated at the GUI and CLI level, which greatly simplifies the process.\nHow to install a Cloud-Init image in Proxmox # In the video, I show how to do all of this using the graphical interface. Personally, I think it\u0026rsquo;s much more convenient, but below I provide the instructions as described in the Proxmox documentation on their website. The instructions on the site are functional, but somewhat outdated. They use an Ubuntu image from way back in 2016 as an example.\nStep 1. Download the official Cloud-Init image # Go to cloud-images.ubuntu.com or a similar resource. For example:\nwget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img Step 2. Import the image into Proxmox # # create a new VM with VirtIO SCSI controller qm create 9000 --memory 2048 --net0 virtio,bridge=vmbr0 --scsihw virtio-scsi-pci # import the downloaded disk to the local-lvm storage, attaching it as a SCSI drive qm set 9000 --scsi0 local-lvm:0,import-from=/path/to/noble-server-cloudimg-amd64.img Step 3. Add the Cloud-Init image as a CD-ROM drive # The next step is to configure the CD-ROM drive that will be used to install Cloud-Init on the virtual machine.\nqm set 9000 --ide2 local-lvm:cloudinit To be able to boot directly from the Cloud-Init image, set the boot order to order=scsi0, so the BIOS only boots from this disk. This speeds up boot time because the VM\u0026rsquo;s BIOS skips checking for a bootable CD-ROM.\nqm set 9000 --boot order=scsi0 Many Cloud-Init images require configuring a serial console and using it as the display. If this configuration doesn\u0026rsquo;t suit a particular image, revert to the default display.\nqm set 9000 --serial0 socket --vga serial0 And as the final step, convert our virtual machine into a template.\nqm template 9000 That\u0026rsquo;s it, the template is ready. From here you can freely create full clones from this template and work with them.\nNetwork features in Proxmox VE 8 # Proxmox VE 8 uses systemd-networkd, so it\u0026rsquo;s important to set the network parameters correctly:\nIf you leave DHCP enabled, Cloud-Init will automatically obtain an IP.\nFor a static IP, fill in the IP Address, Gateway, and DNS fields on the Cloud-Init tab.\nCommands used in the video # Download the image\nwget https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img Rename the image\nmv noble-server-cloudimg-amd64.img noble-server-cloudimg-amd64.qcow2 Set up the serial console on the virtual machine we need\nqm set 700 --serial0 socket --vga serial0 Set the working size of the VM\u0026rsquo;s cloud-init disk\nqemu-img resize noble-server-cloudimg-amd64.qcow2 32G Import the cloud-init image into the virtual machine\nqm disk import 700 noble-server-cloudimg-amd64.qcow2 local Conclusion # Installing a Cloud-Init image in Proxmox VE significantly simplifies infrastructure deployment. Proper image preparation and Cloud-Init configuration allow you to fully automate the VM configuration process, which is especially relevant for DevOps and corporate environments, but of course it can also be used in a homelab.\n","date":"July 20, 2025","externalUrl":null,"permalink":"/en/posts/cloud-init-install-in-proxmox/","section":"Posts","summary":"A detailed guide to setting up CloudInit for automatic server configuration. Covers key files, parameters, and examples for quickly deploying Linux systems with minimal effort.","title":"Installing and Configuring a Cloud-Init Image in Proxmox","type":"posts"},{"content":" Если вам понравилась настоящая статья, то можете поддержать автора став спонсором на бусти (ссылка в разделе контакты).\nProxmox VE - мощная платформа для виртуализации с открытым исходным кодом, которая поддерживает создание шаблонов и использование linked clones - лёгких клонов на основе одного базового образа. Это значительно ускоряет развёртывание новых виртуальных машин и экономит место на диске. Но не подходит для использования в действительно рабочей инфраструктуре.\nВ этой статье вы узнаете, как:\nСоздать шаблон из виртуальной машины. Настроить linked clones. Автоматизировать развёртывание новых ВМ на базе шаблонов. Зачем использовать шаблоны и linked clones? # Если вы часто создаёте однотипные виртуальные машины (это же работает и с LXC контейнером на самом деле) - с Ubuntu, Debian или другими ОС, - использование шаблонов и linked clones поможет:\nСэкономить дисковое пространство и время. В основном время конечно Стандартизировать развёртывание. Упростить CI/CD или DevOps-инфраструктуру. Если конечно вам оно надо Шаг 1. Подготовка виртуальной машины # Создайте обычную ВМ через веб-интерфейс Proxmox (или командную строку, если вы мизантроп). Установите нужную ОС (например, Ubuntu Server). Установите базовый набор пакетов, проведите настройку сети и др. Обязательно установите qemu-guest-agent Шаг 2. Преобразование ВМ в шаблон # Выключите виртуальную машину: qm shutdown 100 Преобразуйте её в шаблон: qm template 100 Теперь ВМ 100 больше нельзя запускать напрямую - это шаблон.\nШаг 3. Создание linked clone # Linked clone - это ВМ, которая использует копию только для изменений, а основная система хранится в шаблоне. Это позволяет:\nМгновенно создавать ВМ. Экономить место. Создание linked clone через CLI (в видео я показываю как это сделать из под графического интерфейса):\nqm clone 100 200 --name ubuntu-clone --full 0 Где 100 - это номер вм-шаблона, а 200 - это id вновь создаваемой вм. ubuntu-clone - это имя (name) новой вм. --full 0 означает linked clone.\nПосле этого можете поменять свойства вновь создаваемой ВМ.\nКогда не стоит использовать linked clones?\nЕсли шаблон удалён - все linked clones станут нерабочими. Нельзя переместить linked clone в другой storage без преобразования в full clone. Миграция между узлами требует shared storage (например, Ceph или NFS).\nЗаключение # Шаблоны и linked clones в Proxmox - отличная возможность автоматизировать и ускорить развёртывание ВМ. Это особенно полезно в тестовых средах, DevOps-сценариях и при работе с облачными образами.\nСсылки # Proxmox VE: Установка и базовая настройка Автоматизация с cloud-init в Proxmox LXC-контейнеры в Proxmox VE: Гайд для новичков Подписывайтесь на stilicho2011 на YouTube - ещё больше видео по Proxmox и системному администрированию!\n","date":"19 July 2025","externalUrl":null,"permalink":"/posts/tempaltes-in-proxmox/","section":"Posts","summary":"Пошаговая инструкция по созданию и настройке шаблонов (Templates) в Proxmox для быстрого развертывания виртуальных машин и контейнеров. Рассмотрены создание шаблонов, сохранение конфигураций и рекомендации по управлению и обновлению образов.","title":"Настройка шаблонов и linked clones в Proxmox VE","type":"posts"},{"content":"","date":"14 July 2025","externalUrl":null,"permalink":"/tags/audiobookshelf/","section":"Tags","summary":"","title":"Audiobookshelf","type":"tags"},{"content":" Audiobookshelf - лучший self-hosted сервер аудиокниг # Если вам понравилась эта статья, вы можете поддержать автора, став спонсором на Boosty (ссылка в разделе «Контакты»).\nВступление # Привет! Ты на сайте Stilicho2011, и сегодня мы поговорим об отличной self-hosted платформе - Audiobookshelf.\nЕсли у тебя накопилось много аудиокниг, и ты хочешь слушать их с любого устройства, синхронизировать прогресс и не зависеть от сторонних сервисов - оставайся, будет интересно!\nЧто такое Audiobookshelf? # Audiobookshelf - это бесплатное и полностью открытое веб-приложение, которое превращает твой сервер в полноценную аудиобиблиотеку.\nОсновные возможности:\nЗагрузка и структурирование аудиокниг Прослушивание через браузер и мобильное приложение Синхронизация прогресса между устройствами Закладки и заметки Полный контроль и конфиденциальность Установка через Docker # Проще всего установить Audiobookshelf с помощью Docker. Вот минимальный docker-compose.yml, который я использовал в ролике:\nservices: audiobookshelf: image: ghcr.io/advplyr/audiobookshelf:latest container_name: audiobookshelf #ports: # - 13378:80 volumes: - /mnt/media:/audiobooks - /mnt/media:/podcasts - /home/user/docker/audiobookshelf/config:/config - /home/user/docker/audiobookshelf/metadata:/metadata environment: - TZ=Europe/Moscow restart: unless-stopped security_opt: - no-new-privileges:true networks: proxy: labels: - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.http.routers.audiobookshelf.entrypoints=http\u0026#34; - \u0026#34;traefik.http.routers.audiobookshelf.rule=Host(`audiobookshelf.domain.ru`)\u0026#34; - \u0026#34;traefik.http.middlewares.audiobookshelf-https-redirect.redirectscheme.scheme=https\u0026#34; - \u0026#34;traefik.http.routers.audiobookshelf.middlewares=audiobookshelf-https-redirect\u0026#34; - \u0026#34;traefik.http.routers.audiobookshelf-secure.entrypoints=https\u0026#34; - \u0026#34;traefik.http.routers.audiobookshelf-secure.rule=Host(`audiobookshelf.domain.ru`)\u0026#34; - \u0026#34;traefik.http.routers.audiobookshelf-secure.tls=true\u0026#34; - \u0026#34;traefik.http.routers.audiobookshelf-secure.service=audiobookshelf\u0026#34; - \u0026#34;traefik.http.services.audiobookshelf.loadbalancer.server.port=80\u0026#34; - \u0026#34;traefik.docker.network=proxy\u0026#34; networks: proxy: external: true Запуск сервиса\ndocker compose up -d После запуска - открой в браузере https://audiobookshelf.domain.ru\nИнтерфейс и возможности # После первого входа можно:\nдобавить папки с аудиокнигами; автоматически подтянуть обложки и описания; использовать удобный встроенный плеер; отслеживать прогресс по книгам; работать с закладками и заметками. Поддерживаемые форматы: .mp3, .m4b (с поддержкой глав), ID3-теги и встроенные обложки. Доступен мобильный режим (через PWA или браузер), а также многопользовательский режим.\nБезопасность и доступ из сети # Рекомендуется разместить Audiobookshelf за reverse-proxy, например Traefik + Authelia, Authentik, Keycloak, Zitadel, или Nginx + Basic Auth.\nТакже стоит подключить SSL-сертификат Let\u0026rsquo;s Encrypt, чтобы слушать книги из любой точки мира по HTTPS.\nПлюсы и минусы # Плюсы # Бесплатно и с открытым исходным кодом. Простой и удобный интерфейс. Отличная синхронизация и мобильная поддержка. Работает полностью локально. Минусы # Нет поиска по содержимому книг. Некоторые форматы требуют перекодировки. Нельзя стримить напрямую из облачных хранилищ. Заключение # Audiobookshelf - отличное self-hosted решение для хранения и прослушивания аудиокниг.\n","date":"14 July 2025","externalUrl":null,"permalink":"/posts/audiobookshelf-install-docker/","section":"Posts","summary":"Полная инструкция по установке и настройке Audiobookshelf для хранения и прослушивания аудиокниг на личном сервере. Рассмотрены все шаги от установки до веб-интерфейса и мобильного доступа.","title":"Audiobookshelf - лучший self-hosted сервер аудиокниг","type":"posts"},{"content":"","date":"July 14, 2025","externalUrl":null,"permalink":"/en/tags/automation/","section":"Tags","summary":"","title":"Automation","type":"tags"},{"content":"","date":"July 14, 2025","externalUrl":null,"permalink":"/en/tags/fedora/","section":"Tags","summary":"","title":"Fedora","type":"tags"},{"content":"","date":"July 14, 2025","externalUrl":null,"permalink":"/en/categories/linkwarden/","section":"Categories","summary":"","title":"Linkwarden","type":"categories"},{"content":" If you enjoyed this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\nWhat is Linkwarden? # Linkwarden is an open-source self-hosted app for managing and archiving bookmarks. It\u0026rsquo;s built for users who value control over their data, want a local copy of important information from the internet, and want a convenient interface for organizing links.\nThe project is actively developed and positions itself as an alternative to services like Pocket, Raindrop.io, and Pinboard, but with an emphasis on privacy, independence, and open source.\nKey features # Archiving web pages # Linkwarden doesn\u0026rsquo;t just save a link - it archives the content of the page (including text, images, and styles), letting you view it even offline. This is especially useful for building a knowledge base and storing scientific materials and blog posts that might disappear from the web.\nFull-fledged search # Full-text search across saved pages is supported. You can find what you need even if you forgot the link or the title.\nTags and collections # Links can be organized using tags and collections, which greatly simplifies navigating a large number of bookmarks.\nMulti-user support # Linkwarden supports a multi-user mode with access rights separation. This is convenient for team work or family use.\nPrivacy and control # By deploying Linkwarden on your own server, you get full control over your data. Authentication via email, Google, GitHub, and other providers is supported through the OAuth 2.0 protocol.\nKey features in table form # Feature Description Page archiving Automatically saves HTML, PDF, and screenshots of added links. Reading mode and annotations Lets you read articles without ads, take notes, and highlight text. Collections and tags Organizes content into hierarchical collections with tags. Collaboration Share collections and manage member permissions. Import / export Supports imports from browsers and export to CSV/HTML. Content search Fast full-text search (via Meilisearch). Integrations (API, SSO) Supports Authentik, a REST API, and custom integrations. Extensions and clients Chrome extension, PWA, Android and iOS apps. AI tags and auto-analysis Determines a link\u0026rsquo;s topic based on the page\u0026rsquo;s content. Wayback Machine Submits links to archive.org for long-term preservation. Simple installation (Docker) # The project ships with ready-made Docker containers. Deployment takes just a couple of minutes:\ngit clone https://github.com/linkwarden/linkwarden cd linkwarden cp .env.example .env docker compose up -d Files used in the video # Docker compose file\nservices: postgres: container_name: postgres_linkwarden image: postgres:16-alpine env_file: .env restart: always volumes: - /home/stilicho/docker/linkwarden/pgdata:/var/lib/postgresql/data networks: - linkwarden #not necessary if you don\u0026#39;t use another postgres instance #- proxy linkwarden: container_name: linkwarden env_file: .env environment: - DATABASE_URL=postgresql://postgres:${POSTGRES_PASSWORD}@postgres:5432/postgres restart: always # build: . # uncomment this line to build from source image: ghcr.io/linkwarden/linkwarden:latest # comment this line to build from source #ports: # - 3000:3000 volumes: - /home/stilicho/docker/linkwarden/data:/data/data depends_on: - postgres networks: - proxy - linkwarden #not necessary if you don\u0026#39;t use another postgres instance labels: - \u0026#34;traefik.enable=true\u0026#34; - \u0026#34;traefik.docker.network=proxy\u0026#34; - \u0026#34;traefik.http.routers.linkwarden.entrypoints=http\u0026#34; - \u0026#34;traefik.http.routers.linkwarden.rule=Host(`linkwarden.domain.ru`)\u0026#34; - \u0026#34;traefik.http.middlewares.linkwarden-https-redirect.redirectscheme.scheme=https\u0026#34; - \u0026#34;traefik.http.routers.linkwarden.middlewares=linkwarden-https-redirect\u0026#34; - \u0026#34;traefik.http.routers.linkwarden-secure.entrypoints=https\u0026#34; - \u0026#34;traefik.http.routers.linkwarden-secure.rule=Host(`linkwarden.domain.ru`)\u0026#34; - \u0026#34;traefik.http.routers.linkwarden-secure.tls=true\u0026#34; - \u0026#34;traefik.http.routers.linkwarden-secure.tls.certresolver=cloudflare\u0026#34; - \u0026#34;traefik.http.routers.linkwarden-secure.service=linkwarden\u0026#34; - \u0026#34;traefik.http.services.linkwarden.loadbalancer.server.port=3000\u0026#34; # make sure the loadbalancer is the last line!!! networks: proxy: external: true linkwarden: external: true Environment file\nNEXTAUTH_URL=https://linkwarden.domain.ru/api/v1/auth # NEXTAUTH_URL=http://localhost:3000/api/v1/auth # Uncomment this if you don\u0026#39;t want to use another Identity Provider NEXTAUTH_SECRET=linkwarden POSTGRES_PASSWORD=Rpassword # SMTP Settings #NEXT_PUBLIC_EMAIL_PROVIDER= #EMAIL_FROM= #EMAIL_SERVER= #BASE_URL= ################# # SSO Providers # ################# #AUTHENTIK_CUSTOM_NAME=Authentik #NEXTAUTH_URL=https://linkwarden.domain.ru/api/v1/auth #NEXT_PUBLIC_AUTHENTIK_ENABLED=true #AUTHENTIK_CUSTOM_NAME=authentik #AUTHENTIK_ISSUER=https://auth.domain.ru/application/o/linkwarden #AUTHENTIK_CLIENT_ID=ID #AUTHENTIK_CLIENT_SECRET=SECRET Comparison with alternatives # Feature Linkwarden Pocket Raindrop.io Wallabag Self-hosted ✅ ❌ ❌ ✅ Page archiving ✅ ❌ ✅ (Pro) ✅ Full-text search ✅ ✅ ✅ ✅ Multi-user ✅ ❌ ✅ ✅ Open source ✅ ❌ ❌ ✅ Use in a homelab # For homelab owners and enthusiasts, Linkwarden is a great addition to a self-hosting stack. It integrates easily with Traefik, Nginx, or Caddy, and can be protected via SSO (for example, with Authentik or Authelia).\nConclusion # Linkwarden is a modern and powerful tool for managing links, built with an emphasis on privacy, convenience, and independence from cloud services. It\u0026rsquo;s a great fit for both personal use and team or family collaboration.\n","date":"July 14, 2025","externalUrl":null,"permalink":"/en/posts/linkwarden/","section":"Posts","summary":"A step-by-step guide to installing and configuring Linkwarden for securely managing your links. Covers server installation, user setup, browser and mobile device integration, and basic security settings.","title":"Linkwarden overview: a modern self-hosted bookmark manager","type":"posts"},{"content":"","date":"July 14, 2025","externalUrl":null,"permalink":"/en/tags/mikrotik/","section":"Tags","summary":"","title":"MikroTik","type":"tags"},{"content":" Introduction # If you enjoyed this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\nFedora Server 42 is the server edition of the popular Fedora distribution, aimed at providing a stable yet modern server environment. In this article, we\u0026rsquo;ll look at the main pros and cons of Fedora Server 42 to figure out whether it\u0026rsquo;s a good fit for a home system or for production servers.\nNote Update. Fedora 42 was released in April 2025 and reached end-of-life on May 13, 2026 - it no longer receives security updates. The current version as of today is Fedora 44 (released April 2026, supported at least through June 2027). All the pros and cons discussed below apply to Fedora Server as such and to its release model - specific version and package numbers should be double-checked against the current release.\n✅ Pros of Fedora Server 42 # 🆕 1. Up-to-date packages # Fedora always ships the newest versions of software:\nLinux kernel 6.9+ Systemd, OpenSSH, libvirt, Podman, and other components - all at their latest versions Fast support for new technologies (for example, cgroups v2, nftables, systemd-homed) This makes Fedora Server ideal for testing and using the latest Linux capabilities.\n🛠 2. Administration tools # Fedora Server ships with the convenient Cockpit - a web interface for managing the server:\nMonitoring CPU, memory, and disk load Managing systemd services Easy configuration of RAID, LVM, logs, and updates Suitable for both beginners and experienced administrators.\n🔐 3. Security by default # Fedora Server includes:\nSELinux in Enforcing mode (protection against unauthorized access) The latest versions of OpenSSL and GnuTLS Frequent security updates This makes Fedora Server a secure choice \u0026ldquo;out of the box.\u0026rdquo;\n🐳 4. Container support # Built-in support for Podman and Toolbox lets you work with containers without Docker:\nOCI image support Systemd integration Support for rootless containers Fedora is actively developing its container technologies.\n🌐 5. An open and free ecosystem # No proprietary repositories Open development by the Red Hat community Regular releases roughly every 6 months ❌ Cons of Fedora Server 42 # ⏳ 1. Short support lifecycle # Fedora Server 42 is supported for only 13 months from its release. This can be a problem:\nRegular upgrades to newer versions are required Upgrade failures via dnf system-upgrade are possible This is inconvenient for long-term projects.\n🧪 2. Cutting-edge → instability # Because of its focus on novelty, you may run into:\nBugs in new packages Compatibility issues with older software Unexpected API/CLI changes Fedora is more of a testing ground than the \u0026ldquo;rock-solid\u0026rdquo; stability of Debian.\n💼 3. Not the best choice for enterprise # Despite its stability, Fedora:\nIsn\u0026rsquo;t certified for most enterprise solutions Has no LTS versions Isn\u0026rsquo;t supported by major vendors to the same extent as RHEL (Red Hat\u0026rsquo;s enterprise version), Debian, or Ubuntu LTS 📦 4. Limited repositories # No packages with proprietary drivers (for example, NVIDIA) Requires connecting third-party repositories (RPM Fusion) This can make installing certain software more difficult.\nConclusion # Fedora Server 42 is a great choice for:\nTesting new technologies Homelab projects Administrators who want to stay \u0026ldquo;on the cutting edge\u0026rdquo; However, if you\u0026rsquo;re looking for:\nMaximum stability\nLong-term support\nVendor support\nit\u0026rsquo;s worth considering alternatives like Rocky Linux, Alma Linux, Debian, or Ubuntu LTS.\nAlternatives # Distribution Support period Target audience Advantages Fedora Server ~13 months Developers, enthusiasts The newest packages, SELinux Rocky Linux 10 years Enterprise Stability, RHEL compatibility Debian Stable ~5 years Conservative users Reliability, LTS Ubuntu Server LTS 5 years + 5 ESM Medium and large business Convenience, commercial support ","date":"July 14, 2025","externalUrl":null,"permalink":"/en/posts/fedora-server-42-in-proxmox/","section":"Posts","summary":"A detailed guide to installing and configuring Fedora Server 42. Covers the main steps: installing the system, configuring users, network services, and a baseline configuration for a secure and stable server.","title":"Pros and cons of Fedora Server 42","type":"posts"},{"content":" Proxmox VE has built-in support for an ACME client, which allows you to automatically obtain and renew SSL certificates from Let\u0026rsquo;s Encrypt. This significantly simplifies securing the Proxmox web interface and API.\nIf you liked this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\n📋 Requirements # A public domain pointed at the IP address of your Proxmox server. Access to DNS records (DNS challenge). Proxmox VE version 6.2 or higher. 🔐 Why use ACME # Automatic certificate renewal. Free of charge. Eliminates browser warnings about an insecure connection. Increases the security of access to the Proxmox web interface. Note It\u0026rsquo;s enough to have a public domain hosted on accessible DNS servers. You don\u0026rsquo;t need any public IPs. We just need a certificate for local domain name resolution.\nIntroduction # Since version 6.2, Proxmox VE includes built-in support for ACME - automatic issuance of SSL certificates from Let\u0026rsquo;s Encrypt. One of the most reliable and universal ways to verify a domain is the DNS Challenge, especially if you don\u0026rsquo;t want to or can\u0026rsquo;t open ports 80/443 to the internet.\nIn this article, we\u0026rsquo;ll walk step by step through setting up the ACME client in Proxmox to obtain an SSL certificate using a DNS API provider.\nRequirements # A public domain pointed at the IP address of your Proxmox server. Access to DNS records (DNS challenge). Proxmox VE version 6.2 or higher. A DNS provider that supports an API (for example, Cloudflare, DuckDNS, DigitalOcean, etc.) Access to Proxmox via SSH or through the web interface Step 1: Enabling ACME in Proxmox # Creating an account # Open the Proxmox web interface and go to Datacenter → ACME → Accounts\nIn the Accounts section, create an account by filling in all the required fields.\nRegistering a plugin # In the Datacenter → ACME → DNS Plugin section, click Add and select the DNS host you need, for example Cloudflare. In the dropdown menu, enter the necessary data you received from your DNS host.\nStep 2: Issuing the certificate # Go to:\nDatacenter → node_name → System → Certificates\nClick ACME → Add\nParameters:\nDomains: proxmox.example.com\nACME Account: the name of the account you created in step 1 Plugin: the name you gave your plugin Click Create\nProxmox will automatically start verification and, upon successful completion, will install the certificate.\nConclusion # Using the DNS Challenge to issue an SSL certificate is a secure and flexible way to protect the Proxmox interface, especially if it\u0026rsquo;s not accessible from outside. Integrating ACME into Proxmox makes this process simple and fully automatic.\nIf you use public DNS providers with API support, setup will take no more than 5 minutes.\nUseful links # Proxmox ACME documentation List of supported DNS plugins Let\u0026rsquo;s Encrypt ","date":"July 14, 2025","externalUrl":null,"permalink":"/en/posts/ssl-termination-in-proxmox/","section":"Posts","summary":"A detailed guide to setting up SSL in Proxmox for secure access to the web interface and API. Covers certificate generation and installation, HTTPS setup, and recommendations for maintaining cluster security.","title":"Setting Up SSL Certificates in Proxmox with the Built-in ACME","type":"posts"},{"content":"","date":"July 14, 2025","externalUrl":null,"permalink":"/en/tags/virtualization/","section":"Tags","summary":"","title":"Virtualization","type":"tags"},{"content":" Virtualization is a powerful tool in the arsenal of a homelab enthusiast or system administrator. One interesting, but rather controversial, case is virtualizing a router, such as OPNsense, pfSense, OpenWrt, or MikroTik CHR, in the Proxmox VE hypervisor. Let\u0026rsquo;s break down the pros and cons of this approach.\nIf you enjoyed this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\nWhy virtualize a router? # Virtualization lets you consolidate your infrastructure: fewer physical devices, centralized management, and flexibility for scaling and redundancy. It\u0026rsquo;s also a great opportunity to test different configurations and systems within a single environment.\nAdvantages of virtualizing a router in Proxmox # Advantage Description Hardware savings A single server acts as a host for several services, including the router. Flexibility It\u0026rsquo;s easy to take snapshots, clones, backups, and roll back changes - especially handy when testing new rules and settings. Monitoring and management Proxmox provides convenient tools for monitoring the resources and state of the VM running the router. Isolation The router in its own VM/LXC is isolated from other services, simplifying security and fault tolerance. SR-IOV and PCI Passthrough support Physical interfaces can be passed straight through into the VM for maximum performance. Disadvantages and risks # Disadvantage Description Dependency on the host If Proxmox \u0026ldquo;goes down,\u0026rdquo; the router goes down with it, which can result in the loss of access to the entire network. More complex boot process Boot order issues: Proxmox has to come up before the router, otherwise there will be no network access. Passing through network interfaces For stable and secure operation, it\u0026rsquo;s advisable to use passthrough or a bridge - this requires experience and careful configuration. Networking can become a bottleneck Especially when using virtual bridges (Linux Bridge, Open vSwitch), which may not provide sufficient throughput. Harder to troubleshoot It\u0026rsquo;s harder to debug network errors across multiple layers of abstraction (Proxmox → VM → router OS). What\u0026rsquo;s better to use: VM or LXC? # VM (virtual machine) - preferable for pfSense and OPNsense, since they\u0026rsquo;re based on FreeBSD and were never designed as an OS meant to run inside a container. LXC - suitable for some Linux-based solutions, but not recommended for critical network services due to the limited level of isolation. Practical tips # Use a UPS and a watchdog to minimize the impact of a host failure. Take regular configuration backups and VM snapshots before updates. Separate management access to Proxmox from the main routed traffic across different interfaces. If you need high availability, consider a Proxmox VE cluster with HA, although this adds complexity and cost. When is it worth virtualizing a router? # It\u0026rsquo;s a good fit if:\nYou already have a stable Proxmox host; You\u0026rsquo;re confident in the reliability of your hardware; You want to save on hardware and power consumption; You need flexibility and redundancy. It\u0026rsquo;s not a good fit if:\nYou\u0026rsquo;re not confident in the stability of the host; You have no alternative access to Proxmox in case of a failure; You\u0026rsquo;re building production infrastructure where 100% availability matters. Conclusion # Virtualizing a router in Proxmox is a powerful but not universal solution. It\u0026rsquo;s a great fit for homelab projects, experiments, and resource savings, but it requires attention to detail and a well-thought-out architecture. If you\u0026rsquo;re ready for those challenges - go for it, the result is worth it!\n","date":"July 14, 2025","externalUrl":null,"permalink":"/en/posts/router-virtualization-pros-and-cons/","section":"Posts","summary":"An overview of the advantages and disadvantages of virtualizing a router (OPNsense, pfSense, MikroTik CHR) in Proxmox VE - when it’s worth it and when it’s better to keep dedicated hardware.","title":"Virtualizing a router in Proxmox: pros, cons, and pitfalls","type":"posts"},{"content":"","date":"14 July 2025","externalUrl":null,"permalink":"/tags/%D0%B2%D0%B8%D1%80%D1%82%D1%83%D0%B0%D0%BB%D0%B8%D0%B7%D0%B0%D1%86%D0%B8%D1%8F/","section":"Tags","summary":"","title":"Виртуализация","type":"tags"},{"content":"","date":"14 July 2025","externalUrl":null,"permalink":"/categories/%D0%BC%D0%B5%D0%B4%D0%B8%D0%B0-%D1%81%D0%B5%D1%80%D0%B2%D0%B5%D1%80%D1%8B/","section":"Categories","summary":"","title":"Медиа-Серверы","type":"categories"},{"content":"","date":"July 13, 2025","externalUrl":null,"permalink":"/en/tags/dns-over-https/","section":"Tags","summary":"","title":"Dns-Over-Https","type":"tags"},{"content":" Introduction # If you enjoyed this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\nDNS is an essential protocol for internet communications. However, the security of this crucial - possibly the most important - protocol can be significantly improved. By default DNS has no encryption, and although authentication systems for DNS do exist, they have faced criticism and have not seen significant adoption. The DNSCrypt protocol was developed specifically to improve DNS security. DNSCrypt is a protocol that encrypts, authenticates, and can anonymize messages between a DNS client and a DNS resolver. It is an open standard with free and open-source reference implementations. It is not tied to any particular company or organization. DNSCrypt version 2 was developed and introduced in 2013 and is perhaps the most widely used encrypted DNS protocol today.\nDNSCrypt helps repel DNS-spoofing attacks. It uses cryptographic signatures to authenticate that responses come from an authorized DNS resolver and remain unmodified.\nIn this article we\u0026rsquo;ll look at installing and configuring the DNSCrypt-proxy plugin on the OPNsense firewall. In addition, I\u0026rsquo;ll provide a list of public DNSCrypt servers and explain the features of the DNSCrypt service.\nInstalling the DNS-proxy plugin # The DNSCrypt-proxy plugin is very easy to install.\nGo to System \u0026gt; Firmware \u0026gt; Plugins. Type \u0026ldquo;dnscrypt\u0026rdquo; into the search box.\nClick the + icon next to the plugin named os-dnscrypt-proxy to install it. You\u0026rsquo;ll then be redirected to the installation menu.\nAfter refreshing the Opnsense menu with F5, a new DNSCrypt-Proxy menu will appear under Services.\nConfiguring the DNSCrypt-proxy plugin # You can enable and configure DNSCrypt-proxy in OPNsense under Services \u0026gt; DNSCrypt-proxy \u0026gt; Configuration. When the daemon initializes, it will look up the list of public DNS servers at https://dnscrypt.info/public-servers. You can view that same list at that link.\nDepending on the settings below, the list can be narrowed down based on your preferences - for example, you can disable logging or restrict logging to IPv4 addresses only. DNS queries will be handled by the two servers that process them fastest. The following settings are available on the DNSCrypt-proxy configuration page.\nEnable DNSCrypt-Proxy: Check this to activate the service\nListen Address: You can configure the addresses and ports to listen on. The default settings are localhost and port 5353. To allow listening on port 53, you must enable Allow Privileged Ports, especially when the system is meant to act as a resolver.\nAllow Privileged Ports: This option lets the service listen on ports below 1024, such as 53\nMax Client Connections: You can set the maximum number of simultaneous client connections you want to accept.\nUse IPv4 Servers: You can allow DNSCrypt-Proxy to use servers with IPv4 support\nUse IPv6 Servers: You can allow DNSCrypt-Proxy to use servers with IPv6 support\nUse DNSCrypt Servers: You can allow DNSCrypt-Proxy to use servers that support the DNSCrypt protocol.\nUse DNS-over-HTTPS Servers: You can allow DNSCrypt-Proxy to use servers that support the DNSCrypt-over-HTTPS protocol.\nRequire DNSSEC: You can allow only DNS resolvers with DNSSEC enabled.\nRequire NoLog: You can allow only DNS resolvers with logging disabled.\nRequire NoFilter: You can allow only DNS resolvers without filtering.\nForce TCP: You can consistently use TCP to connect to upstream servers. This is useful if you need to route all traffic through Tor; otherwise, don\u0026rsquo;t enable this feature.\nProxy: You can use this option to route all TCP connections through a local Tor node. The format should be 127.0.0.1:9050.\nTimeout: You can specify how long, in milliseconds, a DNS query will wait for a response; the default is 2500.\nKeepalive: I think this one\u0026rsquo;s self-explanatory; the default value is set to 30 seconds.\nCert Refresh Delay: You can specify the delay, in minutes, after which certificates will be reloaded; the default value is 240.\nEphemeral Keys: You can generate a separate key for each DNS query. This can improve privacy but may significantly affect CPU load.\nTLS Disable Session Tickets: You can disable TLS session tickets. This improves privacy but also increases latency.\nFallback Resolver: This is the standard unencrypted DNS resolver, intended only for one-off queries to get the initial list of resolvers, and only in case of a failure in the system\u0026rsquo;s DNS configuration. The default value is 9.9.9.9:53, which corresponds to the Quad9 DNS service. You can change it to 1.1.1.1:53 to use Cloudflare.\nBlock IPv6: If you don\u0026rsquo;t use IPv6, you can disable this.\nCache: You can enable the cache if you want to reduce latency.\nCache Size: Specify the desired cache size\nCache Min TTL: Minimum TTL for cached records.\nCache Max TTL: Maximum TTL for cached records.\nCache Negative Min TTL: You can specify the minimum TTL for negatively cached records\nCache Negative Max TTL: You can specify the maximum TTL for negatively cached records\nServer List: You can compile a list of known servers. You can also add your own servers manually. You can find the list of available servers in the section below. If this field is left empty, DNS servers are chosen at random.\nEnable query logs: This option enables/disables local logs.\nDisabled Servers List: You can exclude servers from automatic selection by adding any specific server names here, if you don\u0026rsquo;t want to use them for any reason.\nRelay List: You can set a list of relay servers to be used for relaying to all configured servers.\nManually adding public DNSCrypt servers # The DNSCrypt-proxy plugin lets you add specific public DNSCrypt servers of your choosing. To identify the public DNSCrypt servers you want to use in your OPNSense, you can follow these steps.\nFirst, you need to find the SDNS stamp information for the DNS server. To do this, you can visit https://dnscrypt.info/public-servers/.\nClick on a DNS server, for example adguard-dns, which can be used to remove ads and protect your computer from malware. Copy the value from the SDNS stamp field.\nGo to Services \u0026gt; DNSCrypt-proxy \u0026gt; Configuration in the Opnsense web interface Click on the Servers menu\nClick the Add button with the + icon in the bottom-right corner of the page.\nMake sure the service is activated.\nEnter a name for the DNS resolver, adguard-dns in our case.\nPaste the SDNS stamp you copied in step 3, but without the sdns:// prefix.\nYou can add as many DNS servers as you want. Click Save. This will automatically add the new server configuration, and it will be listed on the Servers page.\nYou can easily edit DNS server settings by clicking the \u0026ldquo;Edit\u0026rdquo; button with the pencil icon at the end of the row.\nYou can delete a DNS server configuration by clicking the Delete button with the trash icon at the end of the row.\nThe plugin itself has all the capabilities needed for ad blocking, building whitelists, and essentially replacing Unbound DNS altogether, but personally I\u0026rsquo;m not a big fan of that option. I use Unbound DNS to the fullest for that part.\nSo I redirect all DNS queries to the built-in Opnsense Unbound DNS.\nForwarding DNS queries from Unbound DNS to DNSCrypt-proxy # You can easily integrate the Unbound DNS server with DNSCrypt-proxy on the OPNSense firewall. In older versions this wasn\u0026rsquo;t as easy. To let Unbound DNS send all DNS queries to DNSCrypt-proxy, you must perform the following steps.\nGo to Services \u0026gt; Unbound DNS \u0026gt; Query Forwarding Click the Add button with the + icon in the bottom-right corner of the Custom Forwarding panel Make sure the Enabled option is turned on Leave the Domain field empty to forward all queries to the DNSCrypt-proxy service. Enter 127.0.0.1 in the Server IP field. Specify the port on which the DNSCrypt-proxy service will listen in the Server Port field, for example 5353\nYou can enter a description for your entry, for example DNSCrypt-proxy\nClick the Save button.\nClick the Apply button to activate query forwarding.\nRunning DNSCrypt-proxy as a standalone DNS server # I\u0026rsquo;ll be honest, I haven\u0026rsquo;t personally done this, because Unbound DNS has much more functionality, but there are people who don\u0026rsquo;t want to run a lot of services and want to keep things minimalist. I\u0026rsquo;ll now explain how to do this.\nDNSCrypt-Proxy can function as a comprehensive, independent DNS alternative to Unbound or Dnsmasq. This configuration removes the need for query forwarding in order to encrypt DNS queries or use DNSBL. To run DNSCrypt-Proxy as a standalone DNS server, you may need to perform the following steps.\nDisable Unbound DNS by going to Services \u0026gt; Unbound DNS \u0026gt; General, then unchecking Enable Unbound.\nDisable Dnsmasq the same way as Unbound DNS, if you\u0026rsquo;re using Dnsmasq.\nNow you can proceed to configuring options such as server selection, building a privacy policy, or configuring caching. Cloaking or DNSBL can be used without any additional configuration.\nVerifying the DNSCrypt-proxy configuration # After installing the DNSCrypt-proxy plugin on the OPNsense firewall, you can verify the configuration in several ways.\nViewing DNSCrypt-proxy logs # After enabling the DNSCrypt-proxy server and enabling the query logging option on your OPNsense, you should see both rejected and forwarded DNS queries from your network on the Log/Queries page, by going to Services \u0026gt; DNSCrypt-proxy \u0026gt; Log/Queries. Below is a sample log file.\nYou can view the available DNS servers your OPNsense has already accessed, along with their response times, on the Log/General page, by going to Services \u0026gt; DNSCrypt-proxy \u0026gt; Log/General.\nUsing the DNS Leak Test site # To verify the service is working, you can use the DNS Leak Test site\nDNSleaktest.com is a widely used website that can be used to determine the DNS resolver in use.\nYou can test your DNSCrypt-proxy settings by performing the following steps.\nGo to dnsleaktest.com.\nClick the Extended test button and wait until the test finishes completely. You should see a list of your DNSCrypt servers, similar to the one in the image below.\nNote Please keep in mind that the test only checks your web browser\u0026rsquo;s configuration. Other software may be using a separate DNS configuration. Incorrect results can also be caused by an HTTP proxy.\nAd blocking # You can add various DNSBLs (DNS blocklists), such as AdAway List, AdGuard List, and Simple Adlist, to block ads, and then visit https://canyoublockit.com/testing/. You should see the Adblocker Test page, similar to the one below.\nWhat are public DNSCrypt servers? # Free resolvers with DNSCrypt support are available worldwide. You can find an interactive list of public DNS servers at https://dnscrypt.info/public-servers\nAn interactive map of public DNS servers is available at https://dnscrypt.info/map\nServers with DNSCrypt OpenNIC support are listed at https://download.dnscrypt.info/dnscrypt-resolvers/v3/opennic.md.\nDNSCrypt servers used for parental control are available at: https://download.dnscrypt.info/dnscrypt-resolvers/v3/parental-control.md.\nAn extensive list of public DNS resolvers supporting the DNSCrypt and DNS-over-HTTP2 protocols is available at: https://download.dnscrypt.info/dnscrypt-resolvers/v3/public-resolvers.md\nDNSCrypt-proxy features # DNSCrypt-proxy is a powerful DNS proxy. It runs on your computer or router, providing local blocking of unwanted content, hiding the destination of your devices\u0026rsquo; traffic, improving application performance through DNS response caching, and enhancing security and privacy by using secure routes for communicating with upstream DNS servers. DNSCrypt-proxy has the following capabilities.\nFiltering: blocks ads, malware, and additional unwanted content. Compatible with all DNS providers.\nEncryption and authentication of DNS communication. Facilitates DNS-over-HTTPS (DoH) using TLS 1.3 and QUIC, DNSCrypt, Anonymized DNS, and ODoH. Client IP addresses can be hidden via Tor, SOCKS, or anonymized DNS relays.\nCloaking, which can be used to provide secure search results for Google, Yahoo, DuckDuckGo, and Bing.\nFiltering with a universal weekly schedule.\nLoad balancing, which lets administrators pick a group of resolvers. In such cases DNSCrypt-proxy will automatically evaluate and monitor their performance, distributing traffic among the fastest available options.\nDNS query monitoring, using various log files for standard and non-standard queries\nDNS caching to reduce latency and improve privacy.\nClear routing of specific domains to specific resolvers\nLocal deprioritization of IPv6 queries to reduce latency on IPv4-only networks\nAutomatic updating of resolver lists\nCompatibility with DNS Security Extensions\nIncludes a local DoH server to facilitate ECH (ESNI).\n","date":"July 13, 2025","externalUrl":null,"permalink":"/en/posts/dns-over-https-setup-in-opnsense/","section":"Posts","summary":"A step-by-step guide to configuring DNS over HTTPS (DoT) in OPNsense for secure and encrypted domain name resolution. Covers configuring DNS services, setting up certificates, and verifying operation on client devices.","title":"Secure DNS: setting up DNS over HTTPS in OPNsense with Unbound DNS","type":"posts"},{"content":"","date":"July 7, 2025","externalUrl":null,"permalink":"/en/tags/dns-over-tls/","section":"Tags","summary":"","title":"Dns-Over-Tls","type":"tags"},{"content":" DNS over TLS (DoT) is a way of encrypting DNS queries that improves privacy and protection against interception by attackers. In OPNsense you can enable DoT using the built-in Unbound DNS server.\nSetting up Unbound DNS, split DNS, fighting ads, or how I stopped using Pi-hole, part 1 # If you enjoyed this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\nThose who watch my videos on YouTube know that I\u0026rsquo;ve long used Opnsense at home as a router and firewall. By default, Opnsense uses Unbound DNS as its DNS resolver. This is actually a very cool solution that ended up replacing a lot of different services for me, giving me just a single point of failure. On one hand that might sound like a downside, but in this particular case it\u0026rsquo;s actually a plus. Why? Because when DNS problems come up - and problems are always DNS - now you only need to look in one place, rather than, as before, wondering whether it\u0026rsquo;s Opnsense or Pi-hole, etc. But let\u0026rsquo;s take things in order.\nUnbound DNS is an open-source recursive DNS server developed by NLnet Labs. It focuses on security, performance, and compliance with modern DNS standards. In OPNsense it is the default DNS server. Unbound works as a recursive resolver, meaning it queries DNS records itself, starting from the root servers, without relying on third-party public resolvers (such as 8.8.8.8).\nList of Unbound DNS features # DNSSEC to verify the authenticity of DNS responses. Local DNS overrides - local DNS records. DNS over TLS (DoT) and DNS over HTTPS (DoH). Access control - configuring DNS access permissions. Caching - query caching. Advantages of using Unbound DNS in OPNsense # Security · Support for DNSSEC. · The ability to enable DNS over TLS, which encrypts DNS traffic. · A minimal number of external trusted points - resolving directly from root servers.\nPerformance · Very fast and lightweight. · Efficient caching: frequent queries are handled instantly. · Works well even on modest hardware (home routers, mini-PCs).\nFlexibility · You can define your own zones, redirects, and ad blocking. · Supports access configuration by IP, interface, and port.\nPrivacy · No dependency on external public DNS providers (unlike Google, Cloudflare, etc.). · No logging of DNS queries unless you configure it manually.\nDeep integration with OPNsense · Managed through the web interface. · Supports DHCP Static Mappings in combination with DNS. · Compatible with firewall, VLAN, and alias settings.\nDownsides and limitations of Unbound DNS # Slow resolution of the first queries With full recursive mode enabled, the first DNS query can be a bit slower than with public resolvers that have a preloaded cache. This is especially noticeable after a reboot or cache clear. Configuration complexity Some features (for example, DNS over TLS, ad blocking) require manual configuration in configuration files or via advanced settings. Not for beginners if you need complex filtering rules or non-standard routing. No built-in ad filtering Unlike Pi-hole or AdGuard Home, Unbound doesn\u0026rsquo;t filter ads out of the box - manual activation of the corresponding functionality is required (in practice, a couple of mouse clicks, so this downside is fairly minor). You have to manually choose blocklists, whose names aren\u0026rsquo;t always intuitive. No nice graphical query logging There\u0026rsquo;s no nice statistics and interface like AdGuard Home or Pi-hole has (there is an unattractive one - actually the graphics there are fine). Setup procedure # All DNS queries are routed in plain text. Your internet provider or a hacker can intercept UDP and TCP traffic on port 53 in the clear in order to compromise DNS queries and responses. For this reason we need to encrypt our DNS queries for security. DNS over TLS (DoT) is a security protocol that uses Transport Layer Security (TLS) to encrypt DNS traffic, and it is one of the most widespread DNS security solutions. The main goal is to improve your security and privacy. Here are a few advantages of DNS over TLS:\nPreventing DNS manipulation by an attacker. Eliminating man-in-the-middle attacks. This is when your request is intercepted and redirected to some phishing site. Preventing surveillance. Well, for a home setup this is admittedly rather far-fetched. Enabling DoT in Opnsense # To configure and enable DoT on the OPNsense firewall, perform the following steps:\nGo to \u0026ldquo;Services\u0026rdquo; → \u0026ldquo;Unbound DNS\u0026rdquo; → \u0026ldquo;DNS over TLS\u0026rdquo; in the OPNsense web interface. Click the \u0026ldquo;Add\u0026rdquo; button with the + icon in the bottom-right corner of the panel. Make sure the \u0026ldquo;Enabled\u0026rdquo; option is checked. You can leave the Domain field empty. By default, if you leave this field empty, all queries will be routed to the specified server. Entering a domain name in this field will route queries for that specific domain to the selected server. Enter the IP address of the DNS server to forward all queries to, for example 8.8.8.8. Set the server port for DoT to 853. Enter the common name of the DNS server (for example, dns.google.com) in the Verify CN field to verify its TLS certificate. DNS-over-TLS is vulnerable to man-in-the-middle attacks if the authenticity of certificates cannot be verified. You can leave the field empty to accept self-signed certificates, but this completely negates the point of what we\u0026rsquo;re doing in this article. Click \u0026ldquo;Save\u0026rdquo;. You can add an IPv6 DNS server as a secondary DNS resolver. Click \u0026ldquo;Apply\u0026rdquo; to activate the settings. In the end you\u0026rsquo;ll get something like this\nConfiguring DNS and DHCP servers # To force all clients on your network to use the DoT servers you defined above, you must correctly configure your DNS and DHCP servers. You can configure the DNS and DHCP services in OPNsense by performing the following steps:\nGo to System → Settings → General in the left menu. Make sure all the DNS server fields are empty. This ensures that DNS traffic is redirected back to the router. Uncheck \u0026ldquo;Allow DNS server list to be overridden by DHCP/PPP on WAN\u0026rdquo; for the DNS server settings. If this option is enabled, the DNS servers provided by the DHCP/PPP server on the wide-area network (WAN) (translating for you: this means your ISP\u0026rsquo;s DNS servers) will be used for their intended functions, such as providing DNS services. And accordingly they will take priority. Click \u0026ldquo;Save\u0026rdquo;. Go to Services → ISC DHCPv4 → LAN in the OPNsense web interface. Make sure the DNS Servers fields are empty. We should use the default system DNS servers. Click \u0026ldquo;Save\u0026rdquo;, then click the \u0026ldquo;Apply Changes\u0026rdquo; button in the top-right corner if the setting was changed. To ensure a secure and trusted environment, it is recommended to use a firewall rule that blocks all outbound DNS traffic on port 53 when using DNS over TLS, which for us uses port 53. If clients decide to query other name servers directly on their own, you can use a NAT redirect rule to send those requests to 127.0.0.1:53, which is the local Unbound service. This guarantees that those queries will definitely be sent over TLS.\nThe list of CN domains used for DoT should be checked for the relevant provider. For Quad9 it is - dns.quad9.net.\n","date":"July 7, 2025","externalUrl":null,"permalink":"/en/posts/dns-over-tls-setup-in-opnsense/","section":"Posts","summary":"Learn how to set up secure DNS over TLS in OPNsense using the built-in Unbound DNS server. A step-by-step guide with configuration and recommendations","title":"Secure DNS: setting up DNS over TLS in OPNsense with Unbound DNS","type":"posts"},{"content":"","date":"July 4, 2025","externalUrl":null,"permalink":"/en/tags/kea-dhcp/","section":"Tags","summary":"","title":"Kea-DHCP","type":"tags"},{"content":" Why switch to Kea DHCP in OPNsense? # By default, OPNsense uses the ISC DHCP server, which is reliable, but not only is it morally outdated - the ISC DHCP project itself has reached end of life (EOL) and is no longer being developed. It has been succeeded by Kea DHCP - a modular, high-performance, and flexible solution from the same developers.\nIf you enjoyed this article, you can support the author by becoming a sponsor on Boosty (link in the contacts section).\nKea DHCP is a powerful alternative to the outdated ISC DHCP, offering a modern approach to IP address distribution and centralized management. If you use OPNsense in production or in a home lab, now is a good time to switch to a more flexible and actively developed solution.\nAdvantages of Kea DHCP # Hot-reload of the lease list - configuration can be changed without restarting. Modular architecture - only the components you need. Support for storing the IP lease list in a database (MySQL/PostgreSQL). REST API - automation and external management. Support for extended logic via hooks and scripts. Active development and support from the community and ISC. Disadvantages of Kea DHCP # Higher load when used in containers on weak hardware. Kea is modern, modular software, but when used with a REST API or a database it can consume more resources. On low-power single-board computers (such as a Raspberry Pi) or LXC containers, performance can be lower than that of the lightweight ISC DHCP.\nLimited failover support (compared to ISC). ISC DHCP implements a classic failover peer protocol. Kea doesn\u0026rsquo;t yet have a full HA mechanism out of the box - or rather, there are certain nuances when configuring it.\nLinks # Official Kea DHCP documentation OPNsense project Kea DHCP on GitHub Kea DHCP has shipped out of the box in Opnsense for quite a while now. The approach I\u0026rsquo;ll describe in this article works both for setting things up from scratch and if you already have a working Opnsense with an ISC DHCP server.\nI put off, or more accurately, I didn\u0026rsquo;t want to start the migration from ISC DHCP to Kea DHCP for a long time, because I was afraid that something would break during the move. What\u0026rsquo;s more, by the standards of how fast networking technologies develop (get adopted), Kea is still a young project. Opnsense users do have some complaints about Kea DHCP - it\u0026rsquo;s still not as stable as one might like, and some may find the feature set lacking. Given all of this, the OPNsense developers began introducing Dnsmasq DHCP \u0026amp; DNS as a lightweight alternative to Kea DHCP. As a result, Opnsense users now have a choice of DHCP server. The developers themselves suggest the following split on their site: Dnsmasq for home and small office use, and Kea DHCP only for business needs. Unfortunately, Dnsmasq DHCP is also still too new a product for Opnsense at this point. There\u0026rsquo;s constantly something that needs fixing. That said, this is to be expected for a new solution. Here\u0026rsquo;s the bottom line. In January 2026, in version 26.1, ISC DHCP was removed from the default installed packages (on fresh installations) and is now available only as a plugin for fans of ancient lore - on existing systems it\u0026rsquo;s pulled in automatically during upgrades. Users are free to decide for themselves which DHCP server option to choose. BUT the default is now DNSMasq. That said, migrating from Kea DHCP to Dnsmasq DHCP and vice versa can be very fast, because both service options support the .csv format. That is, all you need to do is activate the server, do the minimal initial configuration, and feed it a csv file with the static lease data. Unfortunately, the ISC server, being an old technology, doesn\u0026rsquo;t support this format, so migrating from an ISC server on systems with a large number of static leases can take a lot of time. But looking at it from a glass-half-full perspective, this is something you only have to do once.\nConfiguring the KEA DHCP server # So. Let\u0026rsquo;s imagine you have an existing setup with ISC. If you have a fresh installation, then for the most part you\u0026rsquo;ll be doing the same thing, except you won\u0026rsquo;t need to migrate any existing leases. My sequence of actions was as follows. First, with Kea DHCP not yet running (and, accordingly, ISC still running), I made all the necessary configuration changes, entered the interface data and static addresses, then enabled Kea DHCP and immediately disabled ISC DHCP. As a result, the static leases were picked up right away, and the dynamic leases appeared in the Kea DHCP lease lists once the lease term tracked by the ISC server expired, even though it had already been disabled. Everything went off without a hitch. I was actually surprised how smoothly it all went.\nGo to Services, select Kea DHCP\nWe\u0026rsquo;re not interested in the Control Agent, since it\u0026rsquo;s needed for enterprise use. In a home setup you\u0026rsquo;re hardly going to be setting up HA for routers, are you? You\u0026rsquo;re not, right? I\u0026rsquo;m assuming you have a regular IPv4 setup, so I\u0026rsquo;ll show everything using an example for ordinary people. Go to Kea DHCPv4. We won\u0026rsquo;t activate the service just yet, but in the interfaces section, in the drop-down menu, you need to select all the interfaces on which you want your new DHCP server to operate. If you only have two: WAN and LAN, then select only LAN. If you\u0026rsquo;re as abnormal as I am, you\u0026rsquo;ll have more than three interfaces, at minimum: WAN, LAN, and some VLAN. Select anything except WAN. After selecting all the interfaces you need, be sure to check the box next to firewall rules. In the valid lifetime field you can specify the DHCP lease time you want, but the default values should work for most use cases. Naturally, we don\u0026rsquo;t touch HA mode. Here\u0026rsquo;s what I ended up with.\nNow go to the subnets section, click the red plus icon, and manually enter your subnet data. In the subnet field, enter your subnet data. For example, for the default LAN network this looks like 192.168.1.1/24. Set a description in the description field, though that\u0026rsquo;s optional. If you have few subnets, or a good memory, there\u0026rsquo;s no real need for it. In the pool field, you need to manually enter the pool of IP addresses that the DHCP server will hand out automatically. Let\u0026rsquo;s set the address pool the same way it was with ISC, in the format 192.168.1.100 - 192.168.1.199. Uncheck the box next to match client-id. I won\u0026rsquo;t insist that this must be done, but if you want to be able to register IP leases by MAC address in the future - and that\u0026rsquo;s really what you want - the box needs to be unchecked. In the DHCP option data section, check the box next to Auto collect option data. Don\u0026rsquo;t touch anything else.\nSo, here\u0026rsquo;s where we\u0026rsquo;re at. We need to migrate our existing static leases from ISC DHCPv4 to Kea DHCPv4. And here you\u0026rsquo;ll have to do everything by hand. If we were setting everything up from scratch, there\u0026rsquo;d be no real choice, but when you\u0026rsquo;re doing this on a live setup with a lot of leases, it\u0026rsquo;s tedious, since there\u0026rsquo;s no automation. Go to the reservation section, click plus. In the drop-down menu, select the subnet where you want your device to be registered. After that, everything is logical and intuitive. In the ip field, set the desired ip. In the mac address field, enter your device\u0026rsquo;s mac address, set the hostname and description. The last one is optional. And that\u0026rsquo;s it. It took me longer to write this than it\u0026rsquo;ll take you to actually do it. Now go back to the settings section, check the box to activate the Kea DHCP server, go to ISC and deactivate it. That\u0026rsquo;s it. The job is done. After that you can watch in the logs as the device leases in ISC DHCPv4 expire and the devices show up in Kea DHCPv4.\n","date":"July 4, 2025","externalUrl":null,"permalink":"/en/posts/kea-dhcp-setup-in-opnsense/","section":"Posts","summary":"A detailed guide to installing and configuring Kea DHCP in OPNsense. Covers configuring DHCP servers, managing IP address ranges, setting up static assignments, and verifying network operation for reliable and flexible address allocation.","title":"Setting up Kea DHCP server in OPNsense: a modern alternative to ISC DHCP","type":"posts"},{"content":"Welcome to prohomelab.com — a website where experience and knowledge in homelab and IT infrastructure are collected and organized. If something is explained too quickly or not very systematically in a video, you\u0026rsquo;ll find detailed guides and tutorials here:\ninstallation and configuration of server applications (Nextcloud, Proxmox, Docker, Traefik, and others) reviews of self-hosting solutions tips on virtualization, backups, security, and automation The project is not intended to be just a personal knowledge archive. It is also being built with the goal of becoming, together with the community, a knowledge base for beginners, aspiring developers, and anyone building their own IT infrastructure at home.\nIf you\u0026rsquo;d like to help contribute to the blog or share your experience — all contact details can be found in the description.\nAbout Me # There was a time when Pixar was making animated masterpieces. In their movie Ratatouille, the recurring idea was that anyone can cook. We\u0026rsquo;re not in a cartoon, but my experience makes essentially the same point: if you have the desire and your brain is still working, anyone can get into homelabbing without a formal IT background.\nIt may seem strange, but I have absolutely nothing to do with the IT world professionally — my education is entirely in the humanities. However, I\u0026rsquo;ve always been interested in IT. At one point, like many beginners, I had a Synology NAS. Pretty quickly, I found its capabilities limiting. My next NAS was a self-built server running Nas4Free (now known as XigmaNAS). And that was it — I was hooked. When I moved to the beautiful and incredibly convenient TrueNAS Core (compared to XigmaNAS, of course), stopping me became practically impossible.\nThere was virtually no information on managing this operating system in the Russian-speaking part of the internet (and there still isn\u0026rsquo;t, apart from a couple of my own videos). So I had an idea: \u0026ldquo;Why not start making videos about configuring and using TrueNAS Core?\u0026rdquo; Of course, while I was gathering the courage to get started — with absolutely no experience — TrueNAS Scale was released\u0026hellip; and look where it led me!\n","date":"June 29, 2025","externalUrl":null,"permalink":"/en/about/","section":"ProHomeLab — a blog about self-hosting and homelab","summary":"Welcome to prohomelab.com — a website where experience and knowledge in homelab and IT infrastructure are collected and organized. If something is explained too quickly or not very systematically in a video, you’ll find detailed guides and tutorials here:\ninstallation and configuration of server applications (Nextcloud, Proxmox, Docker, Traefik, and others) reviews of self-hosting solutions tips on virtualization, backups, security, and automation The project is not intended to be just a personal knowledge archive. It is also being built with the goal of becoming, together with the community, a knowledge base for beginners, aspiring developers, and anyone building their own IT infrastructure at home.\n","title":"About the Project","type":"page"},{"content":" An article titled _Prohomelab_index # tags: [moc, prohomelab] # ✍️ Overview — Prohomelab # Two-level structure (Hugo page bundle):\n\u0026lt;Category\u0026gt;/ — branch bundle, category page on the site _index.md — category frontmatter, \u0026ldquo;Category Index (ProHomelab)\u0026rdquo; template (still being refined) featured.jpg/png — category cover \u0026lt;article slug\u0026gt;/ — leaf bundle, the article itself index.md — \u0026ldquo;Article Draft (ProHomelab)\u0026rdquo; template, must be named index.md featured.png — article cover 0.png, 1.png\u0026hellip; — remaining screenshots Categories are sections like Proxmox/, Opnsense/, Selfhosting/, Traefik/, Single Sign On/, etc. One category groups several articles on the same topic.\nCreating a new article # If the category doesn\u0026rsquo;t exist yet — create the \u0026lt;Category\u0026gt;/ folder and inside it _index.md (constant frontmatter — copied from an existing category, not from the template). Inside the category, create a subfolder \u0026lt;article slug\u0026gt;/. Inside it — create a note based on the Article Draft (ProHomelab) template, rename the file to index.md. Put the cover in the same place as featured.png/.jpg. Exporting to the site # When the article is ready (draft: false) — copy the entire article subfolder (index.md + images) into content/self-hosting/\u0026lt;slug\u0026gt;/ of the Hugo repository. The category\u0026rsquo;s _index.md is touched separately and rarely — only when creating a new category.\nFull article catalog # By cover # There is no real multi-stage status (idea → draft → review) in the frontmatter, and there won\u0026rsquo;t be — only a binary draft: true/false (the draft column in the table above). Track the \u0026ldquo;in progress but still rough\u0026rdquo; stage through the draft text itself or the publication checklist below.\n✅ Publication checklist # categories/series/tags set draft: false before uploading to the site Future ideas (backlog) # ","externalUrl":null,"permalink":"/en/posts/","section":"Posts","summary":"An article titled _Prohomelab_index # tags: [moc, prohomelab] # ✍️ Overview — Prohomelab # Two-level structure (Hugo page bundle):\n\u003cCategory\u003e/ — branch bundle, category page on the site _index.md — category frontmatter, “Category Index (ProHomelab)” template (still being refined) featured.jpg/png — category cover \u003carticle slug\u003e/ — leaf bundle, the article itself index.md — “Article Draft (ProHomelab)” template, must be named index.md featured.png — article cover 0.png, 1.png… — remaining screenshots Categories are sections like Proxmox/, Opnsense/, Selfhosting/, Traefik/, Single Sign On/, etc. One category groups several articles on the same topic.\n","title":"","type":"posts"},{"content":"","externalUrl":null,"permalink":"/en/authors/","section":"Authors","summary":"","title":"Authors","type":"authors"},{"content":"A series of articles about setting up and integrating CrowdSec — a modern network attack protection system built on a crowdsourced approach.\n","externalUrl":null,"permalink":"/en/posts/crowdsec/","section":"Posts","summary":"A series of articles about setting up and integrating CrowdSec — a modern network attack protection system built on a crowdsourced approach. Step-by-step instructions for installing it in Docker and LXC, connecting it to Traefik and Proxmox, configuring bouncers, and centralized security management.","title":"Crowsdec","type":"posts"},{"content":"A series of articles on deploying and configuring Nextcloud — a powerful cloud solution for storing and syncing files.\nWe cover installation in Docker and LXC, SSL configuration, backups, integration with external databases, and performance optimization.\n","externalUrl":null,"permalink":"/en/posts/nextcloud/","section":"Posts","summary":"A series of articles on deploying and configuring Nextcloud — a powerful cloud solution for storing and syncing files. We cover installation in Docker and LXC, SSL configuration, backups, integration with external databases, and performance optimization.","title":"Nextcloud","type":"posts"},{"content":"summary: A series of articles about Podman — a container engine without a permanently running daemon, compatible with the Docker CLI and OCI images. We cover installation, running and managing containers, Podman Compose, Quadlets as a replacement for systemd units, rootless mode, and networking specifics.\n","externalUrl":null,"permalink":"/en/posts/podman/","section":"Posts","summary":"summary: A series of articles about Podman — a container engine without a permanently running daemon, compatible with the Docker CLI and OCI images. We cover installation, running and managing containers, Podman Compose, Quadlets as a replacement for systemd units, rootless mode, and networking specifics.\n","title":"Podman","type":"posts"},{"content":"A series of articles about Terraform — an infrastructure-as-code (IaC) tool for automating the deployment of servers and virtual machines. We cover configuration basics, working with providers, examples for Proxmox, Docker, and cloud platforms, as well as practical scenarios for home and production environments.\n","externalUrl":null,"permalink":"/en/posts/terraform/","section":"Posts","summary":"A series of articles about Terraform — an infrastructure-as-code (IaC) tool for automating the deployment of servers and virtual machines. We cover configuration basics, working with providers, examples for Proxmox, Docker, and cloud platforms, as well as practical scenarios for home and production environments.","title":"Terraform.","type":"posts"}]