月5000円で月額約26万円相当のホスティング環境を手に入れた話
はじめに
はじめまして!株式会社カウンターワークスでエンジニア一年目としてフロントエンドエンジニアをしている福島です。
ジュニアは作って学べ!ということでコスト気にせず好きにホスティングできる環境がほしいなぁと思っていました。
今回、ある程度整ったオンプレ環境を作れたので紹介します。
もともとはKubernetesをメインに使って構築しようと思っていたのですが、なかなかハードかつtoo muchなのでDocker Swarmに切り替えました、、
ざっくり概要としては cloudflare tunnelで外部公開して、Docker Swarmでコンテナ管理、traefikで各コンテナにルーティングしています。
構成
なぜか自宅にまあまあなスペックの自作PC(Ubuntu24.04)が3台あるのでこちらがリソースになります。
インターネット
↓
Cloudflare (DNS + Proxy + Tunnel)
↓
自宅ルーター (192.168.11.0/24)
↓
┌─────────────────────────────────────────┐
│ Docker Swarm Cluster │
│ │
│ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
│ │ PC1 │ │ PC2 │ │ PC3 │ │
│ │ Master │ │ Worker │ │ Worker │ │
│ └──────────┘ └──────────┘ └──────────┘ │
│ │
│ - Traefik (L7 Reverse Proxy) │
│ - Applications (Rails, etc) │
│ - Databases (MySQL, PostgreSQL) │
│ - Monitoring (Dozzle) │
│ - CI/CD (GitHub Actions Runner) │
└─────────────────────────────────────────┘
トラフィックフロー
1. ユーザー(ブラウザ)
↓ HTTPS
2. Cloudflare DNS (cloudflareでDNS登録してるドメイン)
↓ Cloudflare Proxy(DDoS防御、WAF)
3. Cloudflare Tunnel (暗号化トンネル)
↓ HTTP
4. MasterNode(PC1): Traefik
↓ Host-based Routing
5. Docker Swarm Overlay Network (traefik-public)
↓ Service Discovery
6. Application Container
↓ TCP/3306
7. WorkerNode(PC2・PC3): いろんなアプリケーションやDB
技術スタック紹介
Cloudflareめちゃくちゃ安いかつ便利ですよね、一番好きなサービスかもしれないです。
また、カウンターワークスでもかなりお世話になっているサービスになります。
今回使用した技術やサービスを紹介します。
Cloudflare Tunnel
まず、外部公開するところではCloudflare Tunnelを使ってセキュアかつ簡単に公開できるようにしています。
cloudflare tunnelは好きなPCにcloudflaredをインストールしてcloudflareとのtunnelを作成し、(cloudflareでDNS管理している)ドメインに紐づけることで、対象のドメインに来たアクセスをcloudflareが最初に受け、その後cloudflareで設定したアクセス方法でクライアントとPCが接続できるようになります。
(cloudflare docsからお借りしました。)

こうすることで、固定IPを取得したり、自宅のルーターでポートを開放する必要がなくかなり楽に外部公開が可能です。
また、クライアント to Cloudflare間のリクエストは自動で暗号化してくれるのでSSL周りの設定も不要になります。
(通信プロトコルも選べるのでssh接続も可能で、サーバーに入って作業するときもtunnelを使っています)
ただ、複数のサービスをホスティングするとなったときに、都度tunnelにルートの追加やDNS設定を行わないといけなかったり、複数台のサーバー運用するときにtunnelを複数用意してcloudflareのproxy上で振り分け・管理するのが大変なので、MasterとなるPCをおいてすべてそこで受けた後にtraefikを使って各PC及びサービスにルーティングしています。
Traefikによるルーティング
traefikはリバースプロキシを設定できるOSSのソフトウェアで、ダッシュボードも立ち上がるので視覚的にも優しくルーティング管理できるので採用しました。
(後続のdocker-swarmとも連携しやすい)

中身としては、cloudflare tunnelで *.example.com をMasterPCの http://localhost:80 に繋いであげて、xxx.example.com にくるリクエストをすべてMasterPCに送ります。
MasterPCに来たリクエストをtraefikがRequestURLをみて、事前に紐づけられたrouteのruleから然るべきコンテナにリクエストを流しています。
docker-compose.swarm.yml
version: '3.8'
services:
whoami2:
image: traefik/whoami
networks:
- traefik-public
deploy:
replicas: 2
placement:
constraints:
- node.role == worker
labels: <= ここ
- "traefik.enable=true"
- "traefik.http.routers.testapp2.rule=Host(`xxx.example.com`)"
- "traefik.http.services.testapp2.loadbalancer.server.port=80"
networks:
traefik-public:
external: true
この構成にすることで、traefikに対してサービスの追加をすればいいので、DNSレコードの追加やcloudflare tunnelの設定の追加などが不要になります。
またローカルネットワーク内でのポート管理なども気にする必要がなくなり、traefikのダッシュボード上でサービスの稼働も確認ができます。
ただ、これだけだと複数PCでのサービス管理がかなりしんどいです。
できるだけ楽にそれぞれのPCをクラスター化し、アプリケーションの管理できる方法がないかなと探していたらdocker swarmを見つけました。
Docker Swarm
Docker Swarmはかなりdocker composeライクにクラスター環境をつくれるものになります。
サービス名でのDNS解決
ローカルネットワークとdocker-compose などで他のPCリソース上のDBを指定すると
DATABASE_URL=mysql://user:pass@192.168.100.2:3306/db
みたいにPCに割り当てられたIP指定になるのですが、
docker swarmを使うことで
DATABASE_URL=mysql://user:pass@db-mysql-prod_mysql:3306/db
のように書くことができ、サービス名指定することができます。
これまで結構「あれ、このPCのIPなんだっけな」となっていたのですが、解決されました。
サービスの配置指定
PC1とPC3はGPUを積んでいるので、例えばGPUリソースを使いたいサービスをホスティングしたいとなれば、docker-compose.swarm.yml に以下の様に指定すれば指定が可能です
services:
app:
image: my-app:latest
deploy:
placement:
constraints:
- node.hostname == PC3
ローリングアップデートと冗長構成
そこまで本格的に運用しないのであれば特に不要かもしれませんが、docker swarmが自動的に
- 新しいコンテナを起動
- ヘルスチェック
- 既存のコンテナを停止
とサービスを止めずに更新してくれます。
また、以下の様にyamlで指定すれば、レプリカも作成可能です。
services:
app:
image: my-app:latest
deploy:
replicas: 2 # 2つのコンテナを起動
CI/CD自動化
オンプレ環境ですが、ECSやCloud Runみたいにイメージをビルドして、自動でデプロイできるようにしたかったので、github actionsのrunnerをself-hostedにしてオンプレマシン上でイメージをビルド・マシン上のデプロイスクリプトを実行することで実現しています。
また、自身の管理していないgithubのorganizationなどのレポジトリから
自動デプロイしようとするときも、オンプレ環境側の秘匿情報を他の
organizationに晒さなくてよくなるので、一石二鳥ということで
self-hosted runnerをつくることに意味があります。
具体的なSelf-hosted Runnerのメリット:
- 環境変数(DATABASE_URLなど)をGitHub Secretsに登録不要
- デプロイスクリプトがローカルファイルを直接参照可能
- ファイアウォール設定不要(内部ネットワークで完結)
- クライアントの秘匿情報を外部に出さずに済む
デプロイフロー
開発者
↓ git push origin development
GitHub
↓ Webhook
Self-hosted Runner (PC1)
↓ 1. Checkout
↓ 2. Build (タグ: staging-{COMMIT_HASH})
↓ 3. Deploy (.env.staging 読み込み)
↓ 4. Migrate
↓ 5. Health Check
完了
また、self-hosted runnerの設定は意外と簡単で、ここからRunnerを取得してきてgithub レポジトリと紐づけを行い、サービスのインストール〜起動だけで完結します
GitHubから最新版のRunnerをダウンロード
curl -o actions-runner-linux-x64-2.xxx.x.tar.gz -L \
https://github.com/actions/runner/releases/download/v2.xxx.x/actions-runner-linux-x64-2.xxx.x.tar.gz
展開
tar xzf ./actions-runner-linux-x64-2.xxx.x.tar.gz
トークンの取得場所
リポジトリの Settings → Actions → Runners → New self-hosted runner
./config.sh --url https://github.com/your-org/your-repo \
--token <GITHUB_PROVIDED_TOKEN>
runnerのサービスを起動
# systemdサービスとしてインストール
sudo ./svc.sh install
# サービス起動
sudo ./svc.sh start
# 状態確認
sudo ./svc.sh status
あとはgithub actionsの定義でruns-onに設定してあげる感じになります。
jobs:
deploy:
runs-on: self-hosted
Dozzle(Dockerログビューアー)
オンプレ環境でもCloudWatchみたいに楽にログを見たいし検索もしたいという要望を叶えてくれました。
Dozzleは
- リアルタイム更新
- 検索・フィルタ機能
- 複数コンテナ同時表示
を可能にしてくれるOSSで、画像のようにいつでもWebからログが確認できます。

Cloudflare Access
Dozzleみたいに一般に公開したくないサービスもあります。
一つ一つ cloudflare workerとかでBasic認証を張ったりしてもいいのですが、もっと便利なものをcloudflareは用意してくれてました。
Cloudflare Zero TrustのAccess 機能になります。
このAccess機能はCloudflareでDNS管理していて、ProxyをONにしているドメインであれば利用することができ、ログイン方法の指定やポリシーを設定することができます。
例えば GoogleのOAuth認証を利用して、特定のドメインのメアドであればアクセスを許可するようなことができます。
ステージング環境とかでよくBasic認証を作成することが多いと思いますが、Cloudflareを利用してインフラレイヤーで解決するのも良さそうですね。
おわりに
個人的に早く社内の技術をキャッチアップしたり、バリューを発揮するには同じ技術でなにかアプリケーションを作ってみることが近道だと思っているので、この環境でつくってホスティングしようと思っています。
ちなみに各リソースと電気代、それがクラウドだったらの想定はこんな感じです
| PC | CPU モデル | 物理コア | 論理CPU | メモリ合計 | GPU | GPU メモリ |
|---|---|---|---|---|---|---|
| PC1 | AMD Ryzen 7 5700X | 8 | 16 | 39 GiB | NVIDIA GeForce RTX 3060 Ti | 8 GiB |
| PC2 | AMD Ryzen 5 1600X | 6 | 12 | 31 GiB | なし | - |
| PC3 | AMD Ryzen 7 5700X | 8 | 16 | 31 GiB | NVIDIA GeForce RTX 4060 | 8 GiB |
| 合計 | - | 22 | 44 | 101 GiB | - | 16 GiB |
(100W + 80W + 80W) × 24h × 30日 × 30円/kWh ÷ 1000
= 5,616円/月
もしもAWSのEC2だったら
合計コスト(us-east-1想定)
GPU付き g4dn.2xlarge ×2:$1,082.88 / 月
CPUのみ c7a.4xlarge ×1:$599.42 / 月
合計:
1,082.88 + 599.42 = $1,682.3 / 月
ドル円 156円として、🔥🔥月額約260,000円🔥🔥
停電怖い、、、😱
We are hiring!!
カウンターワークス では一緒に働く仲間を絶賛募集中です。
今後の更なる成長のためには圧倒的に仲間が不足しています。皆さまのご応募お待ちしております!
Appendix
お世話になっているPCたち

ポップアップストアや催事イベント向けの商業スペースを簡単に予約できる「SHOPCOUNTER」と商業施設向けリーシングDXシステム「SHOPCOUNTER Enterprise」を運営しています。エンジニア採用強化中ですので、興味ある方はお気軽にご連絡ください! counterworks.co.jp/
Discussion