现在网络环境风险太大,防范攻击费钱费精力还费时间,所以一直构思在局域网里隔着几层防火墙和路由器安置一台服务器,只开放一个口从CDN平台出去,这样岂不是很安全?
最近看了Cloudflare Tunnel 很符合需求,正好有个项目需要搭建Discourse社区,拿来练手试试。
不过也算是没事找事,Discourse的安装本身很简单,搭配Cloudflare Tunnel 就有了一点小麻烦,不是先装谁后装谁,而是需要一起装,挺纠结的,好在最后成功了,欣慰不少。
废话不多说,上流程~
标题有点标题党了,其实还是要一台服务器的,只是在局域网后面,没公网IP,没80、443端口,甚至没有端口是朝外的,所以我们需要先配置Cloudflare Tunnel。
一、Ubuntu 安装 Cloudflare Tunnel
我用的是Ubuntu20.04,可以在这里查看Cloudflare Tunnel 安装包:Cloudflare Tunnel pkg
单独安装教程可以看这里:点击进入
# Add cloudflare gpg key
sudo mkdir -p --mode=0755 /usr/share/keyrings
curl -fsSL https://pkg.cloudflare.com/cloudflare-main.gpg | sudo tee /usr/share/keyrings/cloudflare-main.gpg >/dev/null
# Add this repo to your apt repositories
echo 'deb [signed-by=/usr/share/keyrings/cloudflare-main.gpg] https://pkg.cloudflare.com/cloudflared focal main' | sudo tee /etc/apt/sources.list.d/cloudflared.list
# install cloudflared
sudo apt-get update && sudo apt-get install cloudflared
1、直接在SSH里登陆Cloudflare:
cloudflared tunnel login
执行后若安装正确则会出现一个登录URL,将该链接复制到任何设备的任何浏览器中登录并选择你想用于内网穿透的域名即可。
成功后会自动生成证书并放置于~/cloudflared/cert.pem中。
2、创建cloudflare tunnel 隧道:
cloudflared tunnel create <Tunnel-NAME>
<Tunnel-NAME>即为隧道名称,随便起就可以。
3、创建配置文件
配置文件的保存位置一般是 ~/.cloudflared/config.yml,也可以自定义随便在哪都可以。 示例配置文件:
tunnel: 6ff42ae2-765d-4adf-8112-31c55c1551ef
credentials-file: /root/.cloudflared/6ff42ae2-765d-4adf-8112-31c55c1551ef.json
protocol: http2
originRequest:
connectTimeout: 30s
noTLSVerify: false
ingress:
- hostname: 1域名.com
service: http://localhost:12345
- hostname: 1域名.com
service: https://localhost:54321
- hostname: ssh.域名.com
service: ssh://localhost:22
- service: http_status:404
其中ingress字段可以创建多个服务,支持的服务类型如下表,新建其他服务前需要到 Cloudflare 控制台对其他子域名进行解析。
控制台对其他子域名进行解析。
服务名称 | 描述 | service 示例值 |
---|---|---|
HTTP/S | 常规网页服务 | https://localhost:8000 |
TCP | TCP 连接 | tcp://localhost:25565 |
SSH | SSH 连接 | ssh://localhost:22 |
RDP | 远程桌面(RDP) | rdp://localhost |
上表转自 Cloudflare 官方文档,仅节选常用协议,若需要完整版请至 Ingress rules 页面查看。
4、将隧道解析到域名上
cloudflared tunnel route dns <Tunnel-NAME> <SUBDOMAIN>
<Tunnel-NAME>填写刚才创建的隧道,<SUBDOMAIN>填写你想用于内网穿透的子域名(该子域名无需提前创建),执行后会自动将隧道解析到该子域名上。 举例:在刚才的配置文件中配置了两个服务,就需要运行两次:
cloudflared tunnel route dns <Tunnel-NAME> 1域名.com
cloudflared tunnel route dns <Tunnel-NAME> ssh.域名.com
5、手动解析其他子域名
打开 Cloudflare 控制台 ,点击左侧网站,点击对应的域名,左侧DNS,找到刚才设置的子域名,将之前自动设置的子域名的解析内容复制到新子域名上就可以。
试运行:
cloudflared --config <config-File> tunnel run <Tunnel-NAME>
# 例:cloudflared --config /root/.cloudflared/config.yml tunnel run mytun
随后稍等一分钟左右,在其他设备上访问刚才解析的子域名测试即可。
6、注册为系统服务(自动安装)
cloudflared service install
7、注册为系统服务(Systemd)
在/etc/systemd/system下创建cloudflared.service文件:
[Unit]
Description=Cloudflare Tunnel
After=network.target
[Service]
ExecStart=cloudflared --config <config-File> tunnel run <Tunnel-NAME>
Restart=always
RestartSec=5
StartLimitInterval=0
[Install]
WantedBy=multi-user.target
保存退出后systemctl enable cloudflared加入开机启动,systemctl start cloudflared启动服务。 查询日志:journalctl -a -u cloudflared。
重新加载systemd配置:
sudo systemctl daemon-reload
启动Cloudflared服务:
sudo systemctl start cloudflared
设置开机启动:
sudo systemctl enable cloudflared
检查服务状态:
sudo systemctl status cloudflared
二、通过Cloudflare Tunnel 安装Discourse:
上面说过,这两个玩意得有先后顺序但又要一起装,因为没有discourse等程序运行跑端口,cloudflare tunnel在启动隧道时会出错,这在几台服务器测试遇到了很多次。而discourse安装时又会检测443端口,内网搞个毛443端口,自相矛盾了属于是。
经过两次测试,发现两个程序要这么搞就行,cloudflared安装后,先不启动,然后安装一半的Discourse,没错,是一半:
Discourse 安装教程来自官方的Docker安装大法:Install-cloud.md
sudo -s
git clone https://github.com/discourse/discourse_docker.git /var/discourse
cd /var/discourse
chmod 700 containers
最好用官方默认的“/var/discourse”地址,别改,这是经过惨痛教训得出的经验。。。
然后下一步安装必定提示错误并失败,但大胆的安装吧~
./discourse-setup
提示443没有,错误一大堆,然后停止安装。
这里先新建个目录,/var/www/discourse ,理论上安装程序之后会自己建立,但我在Ubutun上测试了都不带自己搞,几次了,不得不安装前就先建立好,还最好不要改目录,原因和上面一样,惨痛教训得出的结果。。。
sudo -s
cd /var
mkdir www
cd www
mkdir discourse
然后进入目录 /var/discourse/containers
sudo -s
cd /var/discourse/containers
找到那个叫 app.yml的文件,搞它
vi app.yml
找到端口位置:
expose:
- "80:80" # http
- "443:443" # https
根据上面cloudflare tunnel网址的端口号,把前半端端口改成你设置的
expose:
- "12345:80" # http
- "54321:443" # https
根据配置可以改UNICORN_WORKERS,默认是8,低配可以改成4或者2
UNICORN_WORKERS: 4
修改邮箱smtp配置(再次开启安装程序不会有提示,必须在这里改掉)
别忘记去掉前面的“#”
DISCOURSE_SMTP_ADDRESS: smtp.mail.com
DISCOURSE_SMTP_PORT: 587
DISCOURSE_SMTP_USER_NAME: 你的管理员邮箱地址
DISCOURSE_SMTP_PASSWORD: 你的管理员邮箱密码
DISCOURSE_SMTP_ENABLE_START_TLS: true # (optional, default true)
DISCOURSE_SMTP_DOMAIN: discourse.example.com # (required by some providers)
DISCOURSE_NOTIFICATION_EMAIL: 你的管理员邮箱地址 # (address to send notifications from)
设置SSL的邮箱地址
LETSENCRYPT_ACCOUNT_EMAIL:你的邮箱地址
修改完成后,开始回到目录/var/discourse
cd /var/discourse
这里先开启另一个ssh,然后开启cloudflared:
sudo systemctl start cloudflared
然后回到/var/discourse目录的SSH窗口输入以下命令:
./launcher rebuild app
等待安装完毕就OK了,打开浏览器输入你刚刚设置的域名,不用输入端口号,自动就OK啦~
不过接下来可能会遇到个小麻烦,三次里遇到过两次。
第一次通过浏览器打开安装了discourse的网址会要你注册管理员,邮箱是你上面设置的邮箱,用户名和密码在页面设置。但收不到邮件。。。
打开SSH,进入目录/var/discourse
cd /var/discourse
然后输入:
./launcher enter app
再输入:
rake admin:invite[你设定的管理员地址]
附上 rake详细列表:
rake --tasks
rake about # Li...
rake add_topic_to_quotes # Ad...
rake admin:create # Cr...
rake admin:invite[email] # in...
rake annotate # en...
rake annotate:clean # re...
rake annotate:ensure_all_indexes # en...
rake api_key:create_master[description] # ge...
rake app:template # Ap...
rake app:update # Up...
rake assets:clean[keep] # Re...
rake assets:clobber # Re...
rake assets:environment # Lo...
rake assets:precompile # Co...
rake assets:prestage # pr...
rake autospec # Ru...
rake autospec:swagger # Re...
rake avatars:clean # Cl...
rake avatars:refresh # Re...
rake cache_digests:dependencies # Lo...
rake cache_digests:nested_dependencies # Lo...
rake categories:list # Ou...
rake categories:populate # Cr...
rake chat:install:migrations # Co...
rake compatibility:validate[path] # va...
rake db:create # Cr...
rake db:drop # Dr...
rake db:encryption:init # Ge...
rake db:environment:set # Se...
rake db:fixtures:load # Lo...
rake db:migrate:down # Ru...
rake db:migrate:redo # Ro...
rake db:migrate:status # Di...
rake db:migrate:up # Ru...
rake db:prepare # Ru...
rake db:rebuild_indexes # Re...
rake db:reset # Dr...
rake db:resize:notification_id # Gr...
rake db:schema:cache:clear # Cl...
rake db:schema:cache:dump # Cr...
rake db:schema:dump # Cr...
rake db:schema:load # Lo...
rake db:seed # Lo...
rake db:seed:replant # Tr...
rake db:seed_fu # Lo...
rake db:setup # Cr...
rake db:stats # St...
rake db:status:json # Ch...
rake db:validate_indexes[arg] # Va...
rake db:version # Re...
rake destroy:categories # De...
rake destroy:groups # De...
rake destroy:private_messages # Re...
rake destroy:stats # De...
rake destroy:topics[category,parent_category] # Re...
rake destroy:topics_all_categories # Re...
rake destroy:users # De...
rake dev:config # In...
rake dev:populate # Po...
rake dev:repopulate # Re...
rake dev:reset # Ru...
rake discourse_automation:install:migrations # Co...
rake discourse_narrative_bot:install:migrations # Co...
rake docker:test # Ru...
rake docker:test:setup # Se...
rake email_logs:populate # Cr...
rake emails:fix_mailman_users # ru...
rake emails:import # us...
rake emails:test[email] # Ch...
rake emoji:test # te...
rake emoji:update # up...
rake enqueue_digest_emails # Th...
rake export:categories[category_ids] # Ex...
rake export:category_structure[include_group_users,file_name] # Ex...
rake export:groups[include_group_users,file_name] # Ex...
rake export:translation_overrides # Ex...
rake groups:populate # Cr...
rake hashtags:mark_old_format_for_rebake # Ma...
rake i18n:check # Ch...
rake i18n:reseed[locale] # Up...
rake import:file[file_name] # Im...
rake import:rebake_uncooked_posts_with_events # Re...
rake import:rebake_uncooked_posts_with_polls # Re...
rake import:rebake_uncooked_posts_with_tag[tag_name] # Re...
rake import:update_avatars_from_sso # Up...
rake import:update_first_post_created_at # Up...
rake incoming_emails:truncate_long # re...
rake integration:create_fixtures # Cr...
rake log:clear # Tr...
rake maxminddb:get # do...
rake middleware # Pr...
rake multisite:generate:config # ge...
rake multisite:rollback # ro...
rake plugin:install[repo] # in...
rake plugin:install_all_gems # in...
rake plugin:install_all_official # in...
rake plugin:install_gems[plugin] # in...
rake plugin:migrate:down[plugin] # ru...
rake plugin:pull_compatible[plugin] # pu...
rake plugin:pull_compatible_all # pu...
rake plugin:qunit[plugin,timeout] # ru...
rake plugin:spec[plugin,argv] # ru...
rake plugin:turbo_spec[plugin,argv] # ru...
rake plugin:update[plugin] # up...
rake plugin:update_all # up...
rake plugin:versions # di...
rake poll:migrate_old_polls # Mi...
rake post_revisions:populate # Cr...
rake posts:delete_all_likes # De...
rake posts:delete_word[find,type,ignore_case] # De...
rake posts:fix_letter_avatars # Re...
rake posts:inline_uploads # Co...
rake posts:invalidate_broken_images # in...
rake posts:missing_uploads # Fi...
rake posts:normalize_code # no...
rake posts:rebake # Up...
rake posts:rebake_match[pattern,type,delay] # Re...
rake posts:recover_uploads_from_index # At...
rake posts:refresh_emails[topic_id] # Re...
rake posts:refresh_oneboxes # Up...
rake posts:remap[find,replace,type,ignore_case] # Re...
rake posts:reorder_posts[topic_id] # Re...
rake private_messages:populate[recipient] # Cr...
rake qunit:test[timeout,qunit_path,filter] # Ru...
rake release_note:generate[from,to,repo] # ge...
rake release_note:plugins:generate[from,to,plugin_glob,org] # ge...
rake replies:populate[topic_id,count] # Ad...
rake restart # Re...
rake revisions:debug_deserialization # Pr...
rake scheduler:run_all # ru...
rake secret # Ge...
rake site:export_structure[zip_path] # Ex...
rake site:import_structure[zip_path] # Im...
rake site_settings:export # Ex...
rake site_settings:find_dead # Fi...
rake site_settings:import # Im...
rake smoke:test # ru...
rake stats # Re...
rake tags:populate # Cr...
rake themes:audit # Li...
rake themes:clone_all_official # Cl...
rake themes:install # In...
rake themes:install:archive # In...
rake themes:isolated_test # In...
rake themes:qunit[type,value] # Ru...
rake themes:qunit_all_official # Ru...
rake themes:update # Up...
rake time:zones[country_or_offset] # Li...
rake tmp:clear # Cl...
rake tmp:create # Cr...
rake topics:populate # Cr...
rake user_api_key:create[username] # ge...
rake users:anonymize[username] # An...
rake users:anonymize_all # An...
rake users:change_post_ownership[old_username,new_username,archetype] # Ch...
rake users:disable_2fa[username] # Di...
rake users:list_recent_staff # Li...
rake users:merge[source_username,target_username] # Me...
rake users:populate # Cr...
rake users:recalculate_post_counts # Re...
rake users:rename[old_username,new_username] # Re...
rake users:update_posts[old_username,current_username] # Up...
rake version_bump:beta # St...
rake version_bump:major_stable_merge[version_bump_ref] # St...
rake version_bump:major_stable_prepare[next_major_version_number] # St...
rake version_bump:minor_stable # St...
rake version_bump:stage_security_fixes[base] # sq...
rake yarn:install # In...
rake zeitwerk:check # Ch...
提示:
Granting admin!
Sending email!
OK了,打开浏览器输入网址就可以直接进入页面,登陆你设置的帐号,开始游玩吧~